mirror of
https://github.com/YunoHost-Apps/jappix_ynh.git
synced 2024-09-03 19:26:19 +02:00
419 lines
No EOL
11 KiB
JavaScript
419 lines
No EOL
11 KiB
JavaScript
/*
|
|
|
|
Jappix - An open social platform
|
|
These are the seach tools JS script for Jappix
|
|
|
|
-------------------------------------------------
|
|
|
|
License: AGPL
|
|
Author: Valérian Saliou
|
|
|
|
*/
|
|
|
|
// Bundle
|
|
var Search = (function () {
|
|
|
|
/**
|
|
* Alias of this
|
|
* @private
|
|
*/
|
|
var self = {};
|
|
|
|
|
|
/* Variables */
|
|
self.search_filtered = false;
|
|
|
|
|
|
/**
|
|
* Searches in the user's buddy list
|
|
* @public
|
|
* @param {string} query
|
|
* @return {object}
|
|
*/
|
|
self.processBuddy = function(query) {
|
|
|
|
try {
|
|
// No query submitted?
|
|
if(!query) {
|
|
return;
|
|
}
|
|
|
|
// Wildcard (*) submitted
|
|
if(query == '*') {
|
|
query = '';
|
|
}
|
|
|
|
// Replace forbidden characters in regex
|
|
query = Common.escapeRegex(query);
|
|
|
|
// Create an empty array
|
|
var results = [];
|
|
|
|
// Search regex
|
|
var regex = new RegExp('((^)|( ))' + query, 'gi');
|
|
|
|
// Search in the roster
|
|
var buddies = Roster.getAllBuddies();
|
|
|
|
for(var i in buddies) {
|
|
var xid = buddies[i];
|
|
var nick = Name.getBuddy(xid);
|
|
|
|
// Buddy match our search, and not yet in the array
|
|
if(nick.match(regex) && !Utils.existArrayValue(results, xid)) {
|
|
results.push(xid);
|
|
}
|
|
}
|
|
|
|
// Return the results array
|
|
return results;
|
|
} catch(e) {
|
|
Console.error('Search.processBuddy', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Resets the buddy search tool
|
|
* @public
|
|
* @param {string} destination
|
|
* @return {undefined}
|
|
*/
|
|
self.resetBuddy = function(destination) {
|
|
|
|
try {
|
|
$(destination + ' ul').remove();
|
|
$(destination + ' input').removeClass('suggested');
|
|
} catch(e) {
|
|
Console.error('Search.resetBuddy', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Add the clicked XID to the input
|
|
* @public
|
|
* @param {string} destination
|
|
* @param {string} xid
|
|
* @return {boolean}
|
|
*/
|
|
self.addBuddy = function(destination, xid) {
|
|
|
|
try {
|
|
// Remove the search tool
|
|
self.resetBuddy(destination);
|
|
|
|
// Define a selector
|
|
var input = $(destination + ' input');
|
|
var value = input.val();
|
|
|
|
// Get the old value (if there's another value)
|
|
var old = '';
|
|
|
|
if(value.match(/(^(.+)(,)(\s)?)(\w+)$/))
|
|
old = RegExp.$1;
|
|
|
|
// Add the XID to the "to" input and focus on it
|
|
$(document).oneTime(10, function() {
|
|
input.val(old + xid).focus();
|
|
});
|
|
} catch(e) {
|
|
Console.error('Search.addBuddy', e);
|
|
} finally {
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates the appropriate markup for the search results
|
|
* @public
|
|
* @param {string} destination
|
|
* @return {undefined}
|
|
*/
|
|
self.createBuddy = function(destination) {
|
|
|
|
try {
|
|
// Reset the search engine
|
|
self.resetBuddy(destination);
|
|
|
|
// Get the entered value
|
|
var value = $(destination + ' input').val();
|
|
|
|
// Separation with a comma?
|
|
if(value.match(/^(.+)((,)(\s)?)(\w+)$/))
|
|
value = RegExp.$5;
|
|
|
|
// Get the result array
|
|
var entered = self.processBuddy(value);
|
|
|
|
// Display each result (if any)
|
|
if(entered && entered.length) {
|
|
// Set a special class to the search input
|
|
$(destination + ' input').addClass('suggested');
|
|
|
|
// Append each found buddy in the container
|
|
var regex = new RegExp('((^)|( ))' + value, 'gi');
|
|
|
|
// Initialize the code generation
|
|
var code = '<ul>';
|
|
|
|
for(var b in entered) {
|
|
// Get some values from the XID
|
|
var current = Name.getBuddy(entered[b]).htmlEnc();
|
|
current = current.replace(regex, '<b>$&</b>');
|
|
|
|
// Add the current element to the global code
|
|
code += '<li onclick="return Search.addBuddy(\'' + Utils.encodeOnclick(destination) + '\', \'' + Utils.encodeOnclick(entered[b]) + '\');" data-xid="' + Common.encodeQuotes(entered[b]) + '">' + current + '</li>';
|
|
}
|
|
|
|
// Finish the code generation
|
|
code += '</ul>';
|
|
|
|
// Creates the code in the DOM
|
|
$(destination).append(code);
|
|
|
|
// Put the hover on the first element
|
|
$(destination + ' ul li:first').addClass('hovered');
|
|
|
|
// Hover event, to not to remove this onblur and loose the click event
|
|
$(destination + ' ul li').hover(function() {
|
|
$(destination + ' ul li').removeClass('hovered');
|
|
$(this).addClass('hovered');
|
|
|
|
// Add a marker for the blur event
|
|
$(destination + ' ul').attr('mouse-hover', 'true');
|
|
}, function() {
|
|
$(this).removeClass('hovered');
|
|
|
|
// Remove the mouse over marker
|
|
$(destination + ' ul').removeAttr('mouse-hover');
|
|
});
|
|
}
|
|
} catch(e) {
|
|
Console.error('Search.createBuddy', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Handles the keyboard arrows press when searching
|
|
* @public
|
|
* @param {object} evt
|
|
* @param {string} destination
|
|
* @return {boolean}
|
|
*/
|
|
self.arrowsBuddy = function(evt, destination) {
|
|
|
|
try {
|
|
// Down arrow: 40
|
|
// Up arrown: 38
|
|
|
|
// Initialize
|
|
var code = evt.keyCode;
|
|
|
|
// Not the key we want here
|
|
if((code != 40) && (code != 38))
|
|
return;
|
|
|
|
// Remove the eventual mouse hover marker
|
|
$(destination + ' ul').removeAttr('mouse-hover');
|
|
|
|
// Create the path & get its size
|
|
var path = destination + ' ul li';
|
|
var pSize = $(path).size();
|
|
|
|
// Define the i value
|
|
var i = 0;
|
|
|
|
// Switching yet launched
|
|
if(Common.exists(path + '.hovered')) {
|
|
var index = $(path).attr('data-hovered');
|
|
|
|
if(index)
|
|
i = parseInt(index);
|
|
|
|
if(code == 40)
|
|
i++;
|
|
else
|
|
i--;
|
|
}
|
|
|
|
else if(code == 38)
|
|
i = pSize - 1;
|
|
|
|
// We must not override the maximum i limit
|
|
if(i >= pSize)
|
|
i = 0;
|
|
|
|
// We must not have negative i
|
|
else if(i < 0)
|
|
i = pSize - 1;
|
|
|
|
// Modify the list
|
|
$(path + '.hovered').removeClass('hovered');
|
|
$(path).eq(i).addClass('hovered');
|
|
|
|
// Store the i index
|
|
$(path).attr('data-hovered', i);
|
|
} catch(e) {
|
|
Console.error('Search.arrowsBuddy', e);
|
|
} finally {
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Filters the buddies in the roster
|
|
* @public
|
|
* @param {object} vFilter
|
|
* @return {undefined}
|
|
*/
|
|
self.goFilterBuddy = function(vFilter) {
|
|
|
|
try {
|
|
// Put a marker
|
|
self.search_filtered = true;
|
|
|
|
// Show the buddies that match the search string
|
|
var rFilter = self.processBuddy(vFilter);
|
|
|
|
// Hide all the buddies
|
|
$('#roster .buddy').hide();
|
|
|
|
// Only show the buddies which match the search
|
|
if(!Roster.blist_all) {
|
|
for(var i in rFilter)
|
|
$('#roster .buddy[data-xid="' + escape(rFilter[i]) + '"]:not(.hidden-buddy)').show();
|
|
} else {
|
|
for(var j in rFilter)
|
|
$('#roster .buddy[data-xid="' + escape(rFilter[j]) + '"]').show();
|
|
}
|
|
} catch(e) {
|
|
Console.error('Search.goFilterBuddy', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Resets the buddy filtering in the roster
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.resetFilterBuddy = function() {
|
|
|
|
try {
|
|
// Remove the marker
|
|
self.search_filtered = false;
|
|
|
|
// Show all the buddies
|
|
$('#roster .buddy').show();
|
|
|
|
// Only show available buddies
|
|
if(!Roster.blist_all)
|
|
$('#roster .buddy.hidden-buddy').hide();
|
|
|
|
// Update the groups
|
|
Roster.updateGroups();
|
|
} catch(e) {
|
|
Console.error('Search.resetFilterBuddy', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Funnels the buddy filtering
|
|
* @public
|
|
* @param {number} keycode
|
|
* @return {undefined}
|
|
*/
|
|
self.funnelFilterBuddy = function(keycode) {
|
|
|
|
try {
|
|
// Get the input value
|
|
var input = $('#roster .filter input');
|
|
var cancel = $('#roster .filter a');
|
|
var value = input.val();
|
|
|
|
// Security: reset all the groups, empty or not, deployed or not
|
|
$('#roster .one-group, #roster .group-buddies').show();
|
|
$('#roster .group span').text('-');
|
|
|
|
// Nothing is entered, or escape pressed
|
|
if(!value || (keycode == 27)) {
|
|
if(keycode == 27)
|
|
input.val('');
|
|
|
|
self.resetFilterBuddy();
|
|
cancel.hide();
|
|
}
|
|
|
|
// Process the filtering
|
|
else {
|
|
cancel.show();
|
|
self.goFilterBuddy(value);
|
|
}
|
|
|
|
// Update the groups
|
|
Roster.updateGroups();
|
|
} catch(e) {
|
|
Console.error('Search.funnelFilterBuddy', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Searches for the nearest element (with a lower stamp than the current one)
|
|
* @public
|
|
* @param {number} stamp
|
|
* @param {string} element
|
|
* @return {number}
|
|
*/
|
|
self.sortElementByStamp = function(stamp, element) {
|
|
|
|
try {
|
|
var array = [];
|
|
var i = 0;
|
|
var nearest = 0;
|
|
|
|
// Add the stamp values to the array
|
|
$(element).each(function() {
|
|
var current_stamp = parseInt($(this).attr('data-stamp'));
|
|
|
|
// Push it!
|
|
array.push(current_stamp);
|
|
});
|
|
|
|
// Sort the array
|
|
array.sort();
|
|
|
|
// Get the nearest stamp value
|
|
while(stamp > array[i]) {
|
|
nearest = array[i];
|
|
|
|
i++;
|
|
}
|
|
|
|
return nearest;
|
|
} catch(e) {
|
|
Console.error('Search.sortElementByStamp', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Return class scope
|
|
*/
|
|
return self;
|
|
|
|
})(); |