discourse-legacysite-perl/site/forum.slowtwitch.com/www/static/gforum.js
2024-06-17 22:27:49 +10:00

1135 lines
39 KiB
JavaScript

/*****************************************************************************
* Gossamer Forum - Advanced web community
*
* Website : http://gossamer-threads.com/
* Support : http://gossamer-threads.com/scripts/support/
* Revision : $Id: gforum.js,v 1.89 2008/11/28 23:47:50 brewt Exp $
*
* Copyright (c) 2008 Gossamer Threads Inc. All Rights Reserved.
* Redistribution in part or in whole strictly prohibited. Please
* see LICENSE file for full details.
*****************************************************************************/
/**
* GForum is an object to create a separate name space for GForum javascript
* functions.
*
* Note: all parameters are set in include_common_head.html unless
* otherwise noted.
* @param staticUrl url of static build directory, from GForum/Config/Data
* @param url Base GForum url
* @param helpText help text for the current element on the page.
* @param social_media list of social media sites (not display names!)
* @param user_id the id of the user we want to deal with
* @param timezone_zones hash containing regions as keys with cities as values
* @param timezone_default the default timezone to display
* @param timezone_last_selected
* @param timezone_error_message message to display if ajax fails
* @param timezone_loading_message messate to display while loading time
*/
function GForum() {
this.staticUrl = '';
this.imageUrl = '';
this.gforum_url = '';
this.helpText = '';
// The following two vars get set in 'user_view.html'.
this.social_media = [];
this.user_id = '';
// The following 'timezone' vars are set in 'include_profile_display.html'.
this.timezone_zones = [];
this.timezone_default = '';
this.timezone_last_selected = [];
this.timezone_error_message = '';
this.timezone_loading_message = '';
this.password_strength_lang = [
'Weak',
'Good',
'Strong'
];
this.password_strength_levels = [
0,
40,
70
];
}
$(document).ready(function() {
// For the tooltip icon, we want to display a popup box of text
// further explaining whatever needs explaining. The help text needs
// to be assigned to the title attribute of the tooltip image.
$('.tooltip').hover(
function() {
var text = $(this).attr('title');
$(this).attr('title', '');
var id = $(this).attr('id');
var newId = id+'_tooltip';
// Create an info element after the tooltip icon with the help text
$('body').prepend('<div class="info" id="'+newId+'">'+text+'</div>');
GForum.showInfo(id, newId);
},
function() {
// Remove the tooltip text when we stop hovering over the icon
var id = '#'+$(this).attr('id')+'_tooltip';
var text = $(id).html();
$(id).hide().remove();
$(this).attr('title', text);
}
);
/*************************************************************************
* This binding affects the info/info-parent setup.
* With the info/info-parent setup, clicking on the info-parent causes
* the info div to become visible. This binding forces the info div to
* become invisible again if neither that div, nor it's info-parent
* has been clicked.
*************************************************************************/
$(document).bind("click", function(e) {
var target;
if (!e) { e = window.event; }
if (e.target) {
target = e.target;
} else if (e.srcElement) {
target = e.srcElement;
}
if (target.nodeType == 3) { // defeat Safari bug
target = target.parentNode;
}
/* hide all popups unless we've clicked on that div or it's parent */
if (target.className != 'info' && target.className != 'info-parent') {
$('.info').each(function() {
$(this).hide();
});
}
});
/*************************************************************************
* When we click on an item with the 'favourite' class, we submit an ajax
* request to the server, then we change the child elements in these ways:
*
* - update the favourites image icon
* - update the number of users who've favourited this item
*
* Because the ajax request is really simple, we just assume it will
* work and update the children regardless of the ajax response
*************************************************************************/
$(".favourite").click(function() {
var regex = /(\d+)$/;
var id = regex.exec($(this).attr('id'))[1];
// Get the action to perform
var action = '';
var add = 0;
if ($(this).hasClass('favourite_add')) {
action = 'add';
add = 1;
}
else {
action += 'remove';
add = -1;
}
// Toggle the action class
$(this).toggleClass('favourite_remove');
$(this).toggleClass('favourite_add');
// Save the favourite to the database
var url = GForum.url_get({ 'do': 'json_' + action + '_favourite', 'post_id': id });
$.post(url.url, url.params);
// Increase the favourited counter
var favourite_count_link = $('#favourite_' + id + '_link');
var favourite_count = parseInt(favourite_count_link.html().substr(1, favourite_count_link.html().length -1), 10) + add;
favourite_count_link.html('(' + favourite_count + ')');
if (favourite_count === 0) {
favourite_count_link.addClass('hide');
}
else {
favourite_count_link.removeClass('hide');
}
// Replace the favourite image
var image = $(this).find('img');
var img_url = image.attr('src');
var img_title;
if (action == 'add') {
img_url = img_url.replace('post-favoff', 'post-favon');
img_title = 'Remove Favourite';
}
else {
img_url = img_url.replace('post-favon', 'post-favoff');
img_title = 'Add Favourite';
}
image.attr('src', img_url);
image.attr('title', img_title);
return false;
});
});
GForum.prototype.init_help_text = function(text) {
GForum.helpText = text;
// We can set a 'help-text' element that contains a grayed-out
// string to indicate what default value should be entered.
// When we click on it, we remove the 'gray' class and any
// help text.
$('.help-text').bind("focus", function() {
if ($(this).val() == GForum.helpText) {
$(this).val('');
$(this).removeClass('gray');
}
});
// If we haven't entered any text for our 'help-text' input,
// then when it loses focus, we reset the help string and the
// grayed-out style.
$('.help-text').bind("blur", function() {
if ($(this).val() === '') {
$(this).val(GForum.helpText);
$(this).addClass('gray');
}
});
// If we haven't entered any text for our 'help-text' input,
// then when we hit 'escape' (ie., keycode 0), we reset the
// help string and the grayed-out style.
$('.help-text').bind("keypress", function(e) {
if (e.which === 0 && $(this).val() === '') {
$(this).val('');
$(this).addClass('gray');
$(this).val(GForum.helpText);
$(this).blur();
}
});
};
GForum.prototype.init_username_autocomplete = function () {
$('#autocomplete').autocomplete(
GForum.url_get({ 'do': 'json_user_list' }).url, {
lineSeparator: ',',
matchSubset: 0,
loadingClass: 'input text-area select ac_loading',
inputClass: 'profile-settings text',
onItemSelect: function() {$('#autocomplete').focus();}
}
);
};
/**
* Initialize autocomplete for tags. Ie., when modifying a post and
* specifying tags for that post content, the tag input is handled
* via this function.
*/
GForum.prototype.init_tags = function() {
$('#autocomplete').autocomplete(
GForum.url_get({ 'do': 'json_tags' }).url, {
lineSeparator: ',',
onItemSelect: function() {
$('#autocomplete').focus();
GForum.add_tags($('#autocomplete'));
},
loadingClass: 'input text-area select ac_loading',
inputClass: 'profile-settings'
}
);
// If the user has entered tags, we can assume
// they want them added to the post.
$('#post_write_form').submit(function() {
GForum.add_tags($('#autocomplete'));
});
// Add entered tags when the 'Add' button is clicked, but also
// make sure to cancel the form submission
$('#autocomplete-submit').click(function() {
GForum.add_tags($('#autocomplete'));
return false;
});
// If we hit the enter key when typing in the tag text input
// area, then we want to add all tags in the text input to
// the active tag list.
$('#autocomplete').keypress(function(e) {
if (e.which == 13) {
GForum.add_tags($(this));
}
});
// Now if we click on the image next to the tag
// in the 'selected tags' div, that tag will be
// removed from the active selection.
$('#autocomplete-selected-items .remove-tag').click(function() {
GForum.remove_tag($(this));
return false;
});
};
/**
* Initialize the timezone jquery setup.
* Set default select values and show the current time.
*/
GForum.prototype.init_timezone_select = function(zone_id, init_zone) {
$('#timezone_region').val(zone_id);
GForum.show_zone(zone_id, init_zone);
$('#timezone_region').change(function() {
GForum.show_zone($(this).val());
});
$('#user_timezone').change(function() {
GForum.timezone_last_selected[$('#timezone_region').val()] = $(this).val();
GForum.show_current_time($(this).val());
});
};
/**
* When a city/area has been selected, we need to perform an ajax request
* to get the actual date for that area.
*/
GForum.prototype.show_current_time = function(timezone) {
// First clear the div and set the temporary loading message.
$('#show_current_time').empty();
$('#show_current_time').append(GForum.timezone_loading_message);
// Now do the ajax call.
$.getJSON(GForum.url_get({ 'do': 'json_current_time' }).url, { 'timezone': timezone }, function(response) {
$('#show_current_time').empty();
if (!response.status) {
$('#show_current_time').append(GForum.timezone_error_message);
}
else {
$('#show_current_time').append(response.data);
}
});
};
/**
* When selecting which timezone the user is in, this function handles when
* a specific region is selected. When the region is selected, we want to
* get all cities/areas for that region and populate the 'city/area' select
* with those values.
*/
GForum.prototype.show_zone = function(region, init_zone) {
// For grammatical correctness, we append 's' to 'America' when creating the list.
region = region == 'Americas' ? 'America' : region;
// Remove the node since it's data has grown stale.
$('#user_timezone').empty();
// Cache the timezones locally.
var zones = GForum.timezone_zones[region];
// Append each timezone to the select object.
for (var zone in zones) {
if (typeof zone == 'string') {
// Set the default value and text for this select option.
var value = region + '/' + zones[zone];
var text = zones[zone].replace(/\//g, ' - ').replace(/_/g, ' ');
var selected = '';
if (zones[zone] == 'local') {
value = 'local';
text = GForum.timezone_default;
}
// Set this zone as selected if it's been selected.
if (init_zone && value == init_zone) {
selected = ' selected';
GForum.timezone_last_selected = $('#user_timezone').children().size();
}
else if (!init_zone && GForum.timezone_last_selected[region] && GForum.timezone_last_selected[region] == $('#user_timezone').children().size()) {
selected = ' selected';
}
// Append a new select option to thise select element.
$('#user_timezone').append('<option value="'+value+'"'+selected+'>'+text+'</option>');
}
}
// Update the current time being displayed.
if (!init_zone) {
GForum.show_current_time($('#user_timezone').val());
}
};
/**
* For hidden posts we load two versions of the given post. The default view
* is for the 'hidden' content, which basically just lets you 'click here' to
* show the actual post content. The link has a class of 'show_post', and
* this function handles hiding one and showing the other.
*/
GForum.prototype.init_hidden_posts = function() {
$('.show_post').click(function() {
if ($(this).attr('id').match(/_(\d+)$/)) {
var id = RegExp.$1;
$('#p' + id + '_hide').slideUp();
$('#p' + id).slideDown();
}
return false;
});
};
/**
* For a given form, if there are a set of inputs A and B such
* that some inputs from B must have the same value as some of those
* in group A, then this function follows that mapping to assign
* appropriate values.
*
* @input form_id the id of the form we are submitting.
* @input opts of the form: { mirrored_input_id: id_of_value_to_mirror }
* where we can have as many mirrors and original values as needed.
*/
GForum.prototype.init_mirror_inputs = function(form_id, opts) {
$('#'+form_id).submit(function() {
for (var name in opts) {
if (typeof name == 'string') {
$('#'+name).val($('#'+opts[name]).val());
}
}
});
};
/**
* When we use GForum.helpText to show default text in any input, this
* function is used to clear that default input on form submit.
* @param id id of the form containing the default help text.
*/
GForum.prototype.clear_help_on_submit = function(id) {
$('#'+id).submit(function() {
var text = $('#autocomplete').val();
if (text == GForum.helpText) {
$('#autocomplete').val('');
}
});
};
/**
* For use on the profile-view page.
* We do an ajax request for all the available media types. When we have
* a result, then we call this insert function to insert it into the DOM.
* @param media_type: currently 'flickr', 'youtube', 'delicious' or 'twitter'.
* @param item: the JSON object resulting from the AJAX query.
*/
GForum.prototype.social_media_insert = function(media_type, item) {
if (media_type == "flickr") {
$('#' + media_type + '_content').append('<div class="flickr"><a href="' + item.link + '"><img src="' + item["media:thumbnail"].url + '"/></a></div>');
}
else if (media_type == 'youtube') {
$('#' + media_type + '_content').append('<div class="youtube"><object width="150" height="150"><param name="movie" value="' + item.enclosure.url + '&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="' + item.enclosure.url + '&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="150" height="150"></embed></object></div>');
}
else if (media_type == 'delicious') {
$('#' + media_type + '_content').append('<div><a href="' + item.link + '">' + item.title + '</a></div>');
}
else if (media_type == 'twitter') {
date = item.pubDate.split(' ');
$('#' + media_type + '_content').append('<div><span>' + date[2] + ' ' + date[1] + ', ' + date[4] + '</span<span>' + item.title + '</span></div>');
}
};
/**
* Loads the social media data
* @param int user_id User_id to load the media for
*/
GForum.prototype.load_social_media = function(user_id) {
// Do the AJAX request
$.getJSON(GForum.url_get({ 'do': 'json_social_media_feed' }).url, { 'user_id': user_id }, function(json) {
var data = json.data;
$.each(json.data, function(media_name, media) {
// Remove the spinner icon
$('#' + media_name + '_spinner').remove();
if (media.success == '0') {
$('#' + media_name + '_error').html(media.message);
$('#' + media_name + '_error').show();
}
else {
var items;
if (media.data.feed.channel.item.constructor == Array) {
// We have multiple items
items = media.data.feed.channel.item;
}
else {
items[0] = media.data.feed.channel.item;
}
for (i = 0; i < 5; i++) {
if (typeof items[i] == 'undefined') { break; }
GForum.social_media_insert(media_name, items[i]);
}
}
});
});
};
/**
* Add tags from me to the element identified by '#autocomplete-selected-items'
* @param object me: text input containing string of tags to be entered
*/
GForum.prototype.add_tags = function (me) {
var tags = me.val().toLowerCase().replace(/^\s+/, '').replace(/\s+$/, '').split(/\s*,\s*/);
var $ac_tags = $('#autocomplete-tags');
// get all existing tags so we don't add duplicates
var unique_tags = {};
var current_tags = $ac_tags.val().split(/\s*,\s*/);
for (var i = 0; i < current_tags.length; i++) {
unique_tags[current_tags[i]] = 1;
}
for (var i = 0; i < tags.length; i++) {
var tag = tags[i];
if (!tag.length || unique_tags[tag]) {
continue;
}
unique_tags[tag] = 1;
// add the tag to the list of 'selected tags'
var $button = $('<div class="button-remove remove-tag" title="' + this.html_escape(tag) + '">' + this.html_escape(tag) + '</div>');
$button.click(function () {
GForum.remove_tag($(this));
return false;
});
$('#autocomplete-selected-items').append($button);
// add the tag to the hidden input
$ac_tags.val(($ac_tags.val() ? $ac_tags.val() + ',' : '') + tag);
}
// remove all tags from the input box so we know they've been 'added'
me.val('');
if ($ac_tags.val()) {
$('#autocomplete-selected').slideDown();
}
else {
$('#autocomplete-selected').slideUp();
}
};
/**
* Remove the clicked-upon tag from the active selection.
* @param object me: the tag element that has been clicked
*/
GForum.prototype.remove_tag = function (me) {
// remove the DOM element from the selected items element
var tag = me.attr('title');
me.remove();
var tags = $('#autocomplete-tags').val().split(/\s*,\s*/);
for (var i = 0; i < tags.length; i++) {
if (tags[i] == tag) {
tags.splice(i, 1);
i--;
}
}
$('#autocomplete-tags').val(tags.join(','));
if (tags.length) {
$('#autocomplete-selected').slideDown();
}
else {
$('#autocomplete-selected').slideUp();
}
};
/**
* Show the child popup that is tied to the given parentId
* @param string parentId: Id of the parent object
* @param string thisId: Id of the element to show as a child
* @param int justifyRight: 1-> justify right, otherwise justify left
*/
GForum.prototype.showInfo = function (parentId, thisId, justifyRight) {
var offset = $('#'+parentId).offset();
if (justifyRight) {
$('#'+thisId).css('left', offset.left - $('#'+thisId).width());
}
else {
$('#'+thisId).css('left', offset.left);
}
$('#'+thisId).css('top', offset.top + $('#'+parentId).height());
$('#'+thisId).toggle();
};
/**
* Populates the post reports div
* @param int post_id Post id of post to process
* @param string action Ajax action to call
*
* @return false Returns false to avoid link submission
*/
GForum.prototype.postReportBoxGet = function (post_id, action) {
// Initialize the data store
if (typeof $('#post_report_' + post_id).data('open') == 'undefined') {
$('#post_report_' + post_id).data('open', 0);
$('#post_report_' + post_id).data('last_action', action);
}
if (!$('#post_report_' + post_id).data('open') || $('#post_report_' + post_id).data('last_action') != action) {
// Load the content of the post reports div
$.getJSON(GForum.url_get({ 'do': action }).url, { 'post_id': post_id }, function(json) {
$('#post_report_' + post_id).html(json.data.html);
});
$('#post_report_' + post_id).data('open', 1);
} else {
$('#post_report_' + post_id).data('open', 0);
}
// Open or close the post reports div
if ($('#post_report_' + post_id).data('open') || $('#post_report_' + post_id).data('last_action') == action) {
if ($('#post_report_' + post_id).data('open')) {
$('#post_report_' + post_id).show();
} else {
$('#post_report_' + post_id).hide();
}
}
$('#post_report_' + post_id).data('last_action', action);
return false;
};
/**
* Preopens the post reports div in case a moderator selects a post report
* from the top navigation bar
*/
GForum.prototype.openPostReport = function() {
// Get the anchor from the url
var anchor = document.location.hash;
if (anchor.substr(1, 12) == 'post_report_') {
// Get the post id from the anchor
var post_id = anchor.substr(13);
// Fetch the content and open the post reports div
GForum.postReportBoxGet(post_id, 'json_post_reports_box_get');
}
};
/**
* Initializes the post report elements in the post reports div
* @param int post_id Post id to submit report for
* @param int max_message_length Maximal length for a post report
*/
GForum.prototype.initPostReportBox = function(post_id, max_message_length) {
$('#report_submit_' + post_id).click(function() { return GForum.submitPostReport(post_id); });
$('#report_message_' + post_id).keyup(function() { GForum.restrictPostReportLength(post_id, max_message_length); });
};
/**
* Initializes the post reports elements in the post reports div
* @param int post_id Post id to submit report for
*/
GForum.prototype.initPostReportsBox = function(post_id) {
// Assign the click functions for the moderation links
$('#post_reports_lock_' + post_id).click(function() { return GForum.moderatePostReports(post_id, 'lock'); });
$('#post_reports_mark_processed_' + post_id).click(function() { return GForum.moderatePostReports(post_id, 'mark_processed'); });
// Opens the PM dialog and initializes the PM receipient checkboxes
$('#post_reports_send_pm_' + post_id).click(function() {
$('#post_reports_pm_message_wrapper_' + post_id).slideToggle();
$('.post_reports_pm_user').toggleClass('hide');
$('.post_reports_sub_heading').toggleClass('hide');
return false;
});
// Checks/Unchecks all the PM receipients
$('#post_reports_pm_all_' + post_id).click(function() {
$('.post_reports_pm_user_checkbox_' + post_id).attr('checked', $(this).attr('checked') ? 'checked' : '');
});
// Checks/Unchecks all the PM receipients with the same name
$('.post_reports_pm_user_checkbox_' + post_id).click(function() {
var name = $(this).attr('name');
// Check/Uncheck unique checkboxes
var checked = 'checked';
if (!$(this).attr('checked')) {
checked = '';
}
$("input[name='" + name + "']").attr('checked', checked);
// Check/Uncheck the Send PM to all reporters box
var all_checked = 'checked';
$('.post_reports_pm_user_checkbox_' + post_id).each(function() {
if (!$(this).attr('checked')) {
all_checked = '';
}
});
$('#post_reports_pm_all_' + post_id).attr('checked', all_checked);
});
// Submits a private message to the users
$('#post_reports_submit_pm_' + post_id).click(function() {
GForum.postReportPrivateMessageSend(post_id);
});
};
/**
* AJAX request to submit a post report
* @param int post_id Post id to submit report for
*
* @return false Returns false to avoid form submission
*/
GForum.prototype.submitPostReport = function(post_id) {
var data = {
'do': 'json_post_report_save',
'post_id': post_id,
'message': $('#report_message_' + post_id).val()
};
var url = GForum.url_get(data);
$.post(url.base_url, url.params, function(json) {
if (json.success == 1) {
$('#report_message_' + post_id).val('');
$('#report_error_' + post_id).text('');
$('#post_report_' + post_id).slideToggle();
$('#post_report_' + post_id).data('open', 0);
} else {
$('#report_error_' + post_id).show();
$('#report_error_' + post_id).text(json.message);
}
},
'json');
return false;
};
/**
* Locks a post report or marks it as processed
* @param int post_id Post id to process reports for
* @param string action Action to perform (lock/mark_processed)
*
* @return false Returns false to avoid link submission
*/
GForum.prototype.moderatePostReports = function(post_id, action) {
var data = {
'do': 'json_post_reports_moderate',
'post_id': post_id,
'action': action
};
var url = GForum.url_get(data);
$.post(url.base_url, url.params, function(json) {
// Remove the spacer and the Reports link
if (action == 'mark_processed') {
$('#post_report_' + post_id).slideToggle();
$('#post_reports_link_' + post_id).remove();
$('#post_reports_count_' + post_id).remove();
} else if (action == 'lock') {
$('#post_reports_lock_' + post_id).replaceWith(json.data.lock_timeout);
}
},
'json');
return false;
};
/**
* Restricts the length of the post reports message and shows remaining characters counter
* @param int post_id Post id of post to process
* @param int max_length Maximal length of the post reports message
*
* @return false Returns false to avoid link submission
*/
GForum.prototype.restrictPostReportLength = function(post_id, max_length) {
var report_message_remaining = max_length - $('#report_message_' + post_id).val().length;
if (report_message_remaining <= 0) {
report_message_remaining = 0;
var scroll_top = $('#report_message_' + post_id).scrollTop();
$('#report_message_' + post_id).val($('#report_message_' + post_id).val().substring(0, max_length));
$('#report_message_' + post_id).scrollTop(scroll_top);
}
$('#report_message_remaining_chars_' + post_id).text(report_message_remaining);
};
/**
* Sends a private message to the post reporters and the poster using an AJAX request
* @param int post_id Post id of post to process
*/
GForum.prototype.postReportPrivateMessageSend = function(post_id) {
var msg_input = $("textarea[name='post_reports_pm_message_" + post_id + "']");
var msg_body = msg_input.val();
// Create a unique indexed array containng all the users who get the message
var tmp_pm_users = [];
$('.post_reports_pm_user_checkbox_' + post_id).each(function() {
if ($(this).attr('checked')) {
tmp_pm_users[$(this).val()] = $(this).val();
}
});
if($('#post_reports_pm_poster').attr('checked')) {
tmp_pm_users[$('#post_reports_pm_poster').val()] = $('#post_reports_pm_poster').val();
}
// Remove the indexes from the array
var pm_users = [];
for (pm_user in tmp_pm_users) {
if(typeof pm_user == 'string') {
pm_users.push(pm_user);
}
}
var data = {
'do': 'json_post_reports_message_send',
'post_id': post_id,
'pm_users': pm_users,
'msg_body': msg_body
};
var url = GForum.url_get(data);
$.post(url.base_url, url.params, function(json) {
if (json.success) {
msg_input.val('');
$('#post_reports_pm_message_wrapper_' + post_id).slideToggle();
$('#reports_errors_' + post_id).text('');
$('.post_reports_pm_user').toggle();
} else {
$('#reports_errors_' + post_id).text(json.message);
$('#reports_errors_' + post_id).show();
}
},
"json");
};
/**
* Perform image maximum height/width resizing
* @param object img The image object
* @param int x (optional) Maximum image display width
* @param int y (optional) Maximum image display height
*/
GForum.prototype.resizeImage = function(img, x, y) {
x = x ? x : this.image_max_width;
y = y ? y : this.image_max_height;
var width = 0;
var height = 0;
if (x && x < img.width) {
width = x;
}
if (y && y < img.height) {
height = y;
}
if (width && height) {
if ((img.width > width && img.height <= height) || (img.width > width && img.height > height && width < height)) {
height = 0;
}
else {
width = 0;
}
}
if (width > 0) {
img.width = width;
}
if (height > 0) {
img.height = height;
}
if (width > 0 || height > 0) {
var $link = $('<a href="' + img.src + '" title="Click to view full sized image" target="_blank" />');
var $img = $(img);
$img.replaceWith($link);
$link.append($img);
}
};
/**
* Initializes the user profile google map
* @param hash data Contains the user location information and the default zoom level
*
* @return bool Status of localizing the position on the map
*/
GForum.prototype.init_google_map = function(data) {
// Initialize the map and add the controls
map = new GMap2($('#map_canvas').get(0));
map.addControl(new GSmallMapControl());
map.addControl(new GMenuMapTypeControl());
var point = '';
if (data.longitude !== '' && data.latitude !== '') {
// We use the longitude and latitude information to position the map
point = new GLatLng(data.latitude, data.longitude);
GForum.position_google_map(point, data.zoom_level);
return true;
} else if (data.location !== '') {
// We use the users location to position the map
geocoder = new GClientGeocoder();
return geocoder.getLatLng(data.location, function(point) {
if (point === null) {
// Google couldn't find the location remove the map
$('#map_canvas').remove();
return false;
}
GForum.position_google_map(point, data.zoom_level);
return true;
});
} else {
// This shouldn't happen remove the map
$('#map_canvas').remove();
return false;
}
};
/**
* Centers the map and sets the marker
* @param object point Point to center and where to set the maker
* @param int zoom_level Zoom level of the map
*/
GForum.prototype.position_google_map = function(point, zoom_level) {
map.setCenter(point, zoom_level);
var marker = new GMarker(point);
map.addOverlay(marker);
};
/**
* Code to implement a check all checkbox. Also supports the usage of shift
* clicking to (un)select a range of checkboxes.
* @param string check_boxes The name attribute of all the checkboxes
* @param string check_all A css selector of the check all checkbox (eg. #check_all)
*/
GForum.prototype.init_check_all = function (check_boxes, check_all) {
var $check_all = $(check_all);
var $check_boxes = $('input[name=' + check_boxes + ']:checkbox');
if (!$check_all.length || !$check_boxes.length) {
return;
}
$check_all.click(function () {
$check_boxes.each(function (i, cb) {
cb.checked = $check_all.attr('checked');
});
});
$check_all.removeClass('hide');
var all_checked = true;
// The last (un)checked checkbox
var $last_checked;
$check_boxes.each(function (i, cb) {
var $cb = $(cb);
$cb.click(function (e) {
// Holding shift when clicking on a checkbox (un)selects everything from the previous box to the current one
var shift = e && e.shiftKey && $last_checked && $last_checked.val() != $cb.val();
// Used when 'shift' is true; 1 = first checkbox found, 2 = second checkbox found
var cb_found = 0;
// Whether or not the check all box should be (un)checked
var ac = true;
$check_boxes.each(function (j, cb) {
if (shift) {
if (cb.value == $cb.val() || cb.value == $last_checked.val()) {
++cb_found;
}
if (cb_found == 1) {
cb.checked = $last_checked.attr('checked');
}
}
if (!cb.checked) {
ac = false;
}
});
$check_all.attr('checked', ac);
$last_checked = $cb;
});
if (!$cb.attr('checked')) {
all_checked = false;
}
});
$check_all.attr('checked', all_checked);
};
/**
* Turns links that call functions which are POST request only into a form
* submission. It turns all links that contain the attribute rel="post-only"
* into post requests.
*/
GForum.prototype.init_post_only = function () {
$("a[rel*='post-only']").click(function (e) {
var href = $(this).attr('href');
var q = href.indexOf('?');
var action = q != -1 ? href.substr(0, q) : href;
var query = q != -1 ? href.substr(q + 1) : '';
var form = '<form action="' + GForum.html_escape(action) + '" method="post">';
var args = query.split(/[;&]/);
for (var i = 0; i < args.length; i++) {
if (args[i].match(/([^=]+)=(.*)/)) {
var key = unescape(RegExp.$1);
var val = unescape(RegExp.$2);
form += '<input type="hidden" name="' + GForum.html_escape(key) + '" value="' + GForum.html_escape(val) + '" />';
}
}
form += '</form>';
var $form = $(form);
$(document.body).append($form);
$form.submit();
return false;
});
};
/**
* Initialize the password strength meter.
* @param string pass_input css selector to the password input
* @param string strength_text css selector to the text that will show the password strength
*/
GForum.prototype.init_password_strength = function (pass_input, strength_text) {
var $pass_input = $(pass_input);
var $strength_text = $(strength_text);
if (!$pass_input || !$pass_input.length || !$strength_text || !$strength_text.length) {
return;
}
$pass_input.keyup(function () {
var strength = 'None';
var pass = $pass_input.val();
if (pass.length) {
strength = GForum.password_strength(pass);
}
$strength_text.text(strength).attr('class', 'pass-strength-' + strength.replace(/\s/, '-').toLowerCase());
});
};
/**
* A simple password strength tester.
* @param string password the password to check
*/
GForum.prototype.password_strength = function (password) {
var N = 0;
if (password.match(/\d/)) {
N += 10;
}
if (password.match(/[a-z]/)) {
N += 26;
}
if (password.match(/[A-Z]/)) {
N += 26;
}
if (password.match(/[^a-zA-Z0-9]/)) {
N += 32;
}
// http://en.wikipedia.org/wiki/Password_strength
var entropy = password.length * Math.log(N) / Math.log(2);
var levels = this.password_strength_levels;
for (var i = levels.length - 1; i >= 0; i--) {
if (entropy >= levels[i]) {
return this.password_strength_lang[i];
}
}
return this.password_strength_lang[0];
}
/**
* Initialize the avatar selector.
* @param hash options The options for the avatar selector:
* carousel: css selector of the carousel div
* upload_input: css selector of the upload input (optional)
* selected_input: css selector of the hidden selected avatar input
* jCarouselLite options:
* btnPrev: css selector to the previous button
* btnNext: css selector to the next button
* scroll: the number of avatars to scroll (this should be less or equal to the visible option)
* visible: the number of avatars to show
* start: the avatar to initially show
* (you may also pass in any other jCarouselLite options)
*/
GForum.prototype.init_avatar_selector = function (options) {
$(options.upload_input).change(function () {
if ($(this).val()) {
// The user_icon input needs to be reset to an empty string for uploads to work
$(options.selected_input).val('');
$(options.carousel + ' img').removeClass('avatar_selected');
}
});
$(options.carousel + ' img').click(function () {
var $img = $(this);
var src = $img.attr('src');
$(options.carousel + ' img').removeClass('avatar_selected');
// When jCarousel is in circular mode, it makes a copy of the items, so you
// can't just add the class to the current item
$(options.carousel + " img[src='" + src + "']").addClass('avatar_selected');
var img = src.substr(GForum.imageUrl.length + 1);
if (img == 'avatars/no-avatar.gif') {
img = '';
}
$(options.selected_input).val(img);
});
$(options.carousel).jCarouselLite(options);
};
GForum.prototype.html_escape = function (text) {
return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
};
GForum.prototype.html_unescape = function (text) {
return text.replace(/&quot;/gi, '"').replace(/&gt;/gi, '>').replace(/&lt;/gi, '<').replace(/&amp;/gi, '&');
};
/**
* Parses GForum.url, breaks it into its components, merges params arg into query string and returns a hash containing:
* url - Complete url with merged query string (GET requests)
* base_url Base url without query string (POST requests)
* params Merged query string components (POST requests)
*
* @param params Parameters to merge into the query string
*
* @return Hash containing the url, base_url and params
*/
GForum.prototype.url_get = function(params) {
var url = GForum.gforum_url;
// Parse the url
var regex = /^(.*?)(?:\?(.*?))?(?:#(.*?))?$/;
var url_parts = regex.exec(url);
var base_url = url_parts[1];
var query_string = url_parts[2];
// Parse the query string and add the parameters to params
if(typeof query_string == 'string') {
$.each(query_string.split(';'), function () {
var pieces = this.split('=');
params[pieces[0]] = pieces[1];
});
}
// Create the new query_string
var query_string_pieces = [];
if(typeof params == 'object') {
$.each(params, function (key, value) {
query_string_pieces.push(key + '=' + value);
});
}
query_string = query_string_pieces.join(';');
url = base_url;
if (query_string) {
url += '?' + query_string;
}
return { 'url': url, 'base_url': base_url, 'params': params };
};
var GForum = new GForum();