Empty commit

This commit is contained in:
Git 2013-09-08 08:00:57 +00:00
parent d8114b70fe
commit 7efef001cb
28 changed files with 681 additions and 131 deletions

View File

@ -25,7 +25,7 @@ define('SQLLOGIN', '');//The MySQL login
define('SQLPASS', ''); //The MySQL password define('SQLPASS', ''); //The MySQL password
define('SQLDB', 'gazelle'); //The MySQL database to use define('SQLDB', 'gazelle'); //The MySQL database to use
define('SQLPORT', 3306); //The MySQL port to connect on define('SQLPORT', 3306); //The MySQL port to connect on
define('SQLSOCK', '/var/run/mysqld/mysql.sock'); define('SQLSOCK', '/var/run/mysqld/mysqld.sock');
// Memcached details // Memcached details
$MemcachedServers = array( $MemcachedServers = array(
@ -58,12 +58,13 @@ if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 80) {
// Site settings // Site settings
if (PHP_VERSION_ID < 50307) { if (PHP_VERSION_ID < 50307) {
die("PHP version 5.3.7 or later is highly recommended for gazelle's password hashing methods.". die("PHP version 5.3.7 or later is highly recommended for gazelle's password hashing methods.".
" Uncomment line ".__LINE__." in file ".__FILE__." if you want to continue to use this version."); " Comment out line ".__LINE__." in file ".__FILE__." if you want to continue to use this version.");
define('CRYPT_HASH_PREFIX', '$2a$07$'); // Crypt salt prefix for hash settings. See http://php.net/crypt for details define('CRYPT_HASH_PREFIX', '$2a$07$'); // Crypt salt prefix for hash settings. See http://php.net/crypt for details
} else { } else {
define('CRYPT_HASH_PREFIX', '$2y$07$'); define('CRYPT_HASH_PREFIX', '$2y$07$');
} }
define('DEBUG_MODE', false); //Set to false if you dont want everyone to see debug information, can be overriden with 'site_debug' define('DEBUG_MODE', false); //Set to false if you dont want everyone to see debug information, can be overriden with 'site_debug'
define('DEBUG_WARNINGS', true); //Set to true if you want to see PHP warnings in the footer
define('OPEN_REGISTRATION', true); //Set to false to disable open regirstration, true to allow anyone to register define('OPEN_REGISTRATION', true); //Set to false to disable open regirstration, true to allow anyone to register
define('USER_LIMIT', 5000); //The maximum number of users the site can have, 0 for no limit define('USER_LIMIT', 5000); //The maximum number of users the site can have, 0 for no limit
define('STARTING_INVITES', 0); //# of invites to give to newly registered users define('STARTING_INVITES', 0); //# of invites to give to newly registered users
@ -149,7 +150,7 @@ $Formats = array('MP3', 'FLAC', 'Ogg Vorbis', 'AAC', 'AC3', 'DTS');
$Bitrates = array('192', 'APS (VBR)', 'V2 (VBR)', 'V1 (VBR)', '256', 'APX (VBR)', 'V0 (VBR)', 'q8.x (VBR)', '320', 'Lossless', '24bit Lossless', 'Other'); $Bitrates = array('192', 'APS (VBR)', 'V2 (VBR)', 'V1 (VBR)', '256', 'APX (VBR)', 'V0 (VBR)', 'q8.x (VBR)', '320', 'Lossless', '24bit Lossless', 'Other');
$Media = array('CD', 'DVD', 'Vinyl', 'Soundboard', 'SACD', 'DAT', 'Cassette', 'WEB'); $Media = array('CD', 'DVD', 'Vinyl', 'Soundboard', 'SACD', 'DAT', 'Cassette', 'WEB');
$CollageCats = array(0=>'Personal', 1=>'Theme', 2=>'Genre introduction', 3=>'Discography', 4=>'Label', 5=>'Staff picks', 6=>'Charts'); $CollageCats = array(0=>'Personal', 1=>'Theme', 2=>'Genre introduction', 3=>'Discography', 4=>'Label', 5=>'Staff picks', 6=>'Charts', 7=>'Artists');
$ReleaseTypes = array(1=>'Album', 3=>'Soundtrack', 5=>'EP', 6=>'Anthology', 7=>'Compilation', 9=>'Single', 11=>'Live album', 13=>'Remix', 14=>'Bootleg', 15=>'Interview', 16=>'Mixtape', 21=>'Unknown'); $ReleaseTypes = array(1=>'Album', 3=>'Soundtrack', 5=>'EP', 6=>'Anthology', 7=>'Compilation', 9=>'Single', 11=>'Live album', 13=>'Remix', 14=>'Bootleg', 15=>'Interview', 16=>'Mixtape', 21=>'Unknown');
//$ForumCats = array(1=>'Site', 5=>'Community', 10=>'Help', 8=>'Music', 20=>'Trash'); //No longer needed //$ForumCats = array(1=>'Site', 5=>'Community', 10=>'Help', 8=>'Music', 20=>'Trash'); //No longer needed

View File

@ -203,12 +203,9 @@ public function php_error_handler($Level, $Error, $File, $Line) {
$File = str_replace(SERVER_ROOT, '', $File); $File = str_replace(SERVER_ROOT, '', $File);
$Error = str_replace(SERVER_ROOT, '', $Error); $Error = str_replace(SERVER_ROOT, '', $Error);
/* if (defined('DEBUG_WARNINGS')) {
//Hiding "session_start(): Server 10.10.0.1 (tcp 11211) failed with: No route to host (113)" errors
if ($Call != "session_start") {
$this->Errors[] = array($Error, $File.':'.$Line, $Call, $Args); $this->Errors[] = array($Error, $File.':'.$Line, $Call, $Args);
} }
*/
return true; return true;
} }

View File

@ -289,7 +289,7 @@ public static function has_donor_forum($UserID) {
public static function is_mod($UserID) { public static function is_mod($UserID) {
$Permissions = Permissions::get_permissions_for_user($UserID); $Permissions = Permissions::get_permissions_for_user($UserID);
return $Permissions['users_mod']; return isset($Permissions['users_mod']) && $Permissions['users_mod'];
} }
@ -376,9 +376,21 @@ public static function get_enabled_rewards($UserID) {
$SpecialRank = self::get_special_rank($UserID); $SpecialRank = self::get_special_rank($UserID);
$HasAll = $SpecialRank == 3; $HasAll = $SpecialRank == 3;
if ($Rank >= 1 || $HasAll) { $Rewards = array(
'HasAvatarMouseOverText' => false,
'HasCustomDonorIcon' => false,
'HasDonorForum' => false,
'HasDonorIconLink' => false,
'HasDonorIconMouseOverText' => false,
'HasProfileInfo1' => false,
'HasProfileInfo2' => false,
'HasProfileInfo3' => false,
'HasProfileInfo4' => false,
'HasSecondAvatar' => false);
} // if ($Rank >= 1 || $HasAll) {
//
// }
if ($Rank >= 2 || $HasAll) { if ($Rank >= 2 || $HasAll) {
$Rewards["HasDonorIconMouseOverText"] = true; $Rewards["HasDonorIconMouseOverText"] = true;
$Rewards["HasProfileInfo1"] = true; $Rewards["HasProfileInfo1"] = true;

View File

@ -127,7 +127,7 @@ public static function get_ratio_html($Dividend, $Divisor, $Color = true) {
* @param int $Decimal floor to n decimals (e.g. subtract .005 to floor to 2 decimals) * @param int $Decimal floor to n decimals (e.g. subtract .005 to floor to 2 decimals)
* @return boolean|string * @return boolean|string
*/ */
public function get_ratio ($Dividend, $Divisor, $Decimal = 2) { public static function get_ratio($Dividend, $Divisor, $Decimal = 2) {
if ($Divisor == 0 && $Dividend == 0) { if ($Divisor == 0 && $Dividend == 0) {
return false; return false;
} }

View File

@ -12,9 +12,10 @@ class Forums {
* @return array holding thread information. * @return array holding thread information.
*/ */
public static function get_thread_info($ThreadID, $Return = true, $SelectiveCache = false) { public static function get_thread_info($ThreadID, $Return = true, $SelectiveCache = false) {
if ((!$ThreadInfo = G::$Cache->get_value('thread_' . $ThreadID . '_info')) || !isset($ThreadInfo['OP'])) { if ((!$ThreadInfo = G::$Cache->get_value('thread_' . $ThreadID . '_info')) || !isset($ThreadInfo['Ranking'])) {
$QueryID = G::$DB->get_query_id(); $QueryID = G::$DB->get_query_id();
G::$DB->query("SELECT G::$DB->query(
"SELECT
t.Title, t.Title,
t.ForumID, t.ForumID,
t.IsLocked, t.IsLocked,
@ -23,10 +24,11 @@ public static function get_thread_info($ThreadID, $Return = true, $SelectiveCach
t.LastPostAuthorID, t.LastPostAuthorID,
ISNULL(p.TopicID) AS NoPoll, ISNULL(p.TopicID) AS NoPoll,
t.StickyPostID, t.StickyPostID,
t.AuthorID as OP t.AuthorID as OP,
t.Ranking
FROM forums_topics AS t FROM forums_topics AS t
JOIN forums_posts AS fp ON fp.TopicID = t.ID JOIN forums_posts AS fp ON fp.TopicID = t.ID
LEFT JOIN forums_polls AS p ON p.TopicID=t.ID LEFT JOIN forums_polls AS p ON p.TopicID=t.ID
WHERE t.ID = '$ThreadID' WHERE t.ID = '$ThreadID'
GROUP BY fp.TopicID"); GROUP BY fp.TopicID");
if (G::$DB->record_count() == 0) { if (G::$DB->record_count() == 0) {
@ -35,17 +37,19 @@ public static function get_thread_info($ThreadID, $Return = true, $SelectiveCach
$ThreadInfo = G::$DB->next_record(MYSQLI_ASSOC, false); $ThreadInfo = G::$DB->next_record(MYSQLI_ASSOC, false);
if ($ThreadInfo['StickyPostID']) { if ($ThreadInfo['StickyPostID']) {
$ThreadInfo['Posts']--; $ThreadInfo['Posts']--;
G::$DB->query("SELECT G::$DB->query(
p.ID, "SELECT
p.AuthorID, p.ID,
p.AddedTime, p.AuthorID,
p.Body, p.AddedTime,
p.EditedUserID, p.Body,
p.EditedTime, p.EditedUserID,
ed.Username p.EditedTime,
FROM forums_posts as p ed.Username
LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID FROM forums_posts as p
WHERE p.TopicID = '$ThreadID' AND p.ID = '" . $ThreadInfo['StickyPostID'] . "'"); LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID
WHERE p.TopicID = '$ThreadID'
AND p.ID = '" . $ThreadInfo['StickyPostID'] . "'");
list ($ThreadInfo['StickyPost']) = G::$DB->to_array(false, MYSQLI_ASSOC); list ($ThreadInfo['StickyPost']) = G::$DB->to_array(false, MYSQLI_ASSOC);
} }
G::$DB->set_query_id($QueryID); G::$DB->set_query_id($QueryID);
@ -69,7 +73,7 @@ public static function get_thread_info($ThreadID, $Return = true, $SelectiveCach
*/ */
public static function check_forumperm($ForumID, $Perm = 'Read') { public static function check_forumperm($ForumID, $Perm = 'Read') {
$Forums = self::get_forums(); $Forums = self::get_forums();
if (G::$LoggedUser['CustomForums'][$ForumID] == 1) { if (isset(G::$LoggedUser['CustomForums'][$ForumID]) && G::$LoggedUser['CustomForums'][$ForumID] == 1) {
return true; return true;
} }
if ($ForumID == DONOR_FORUM && Donations::has_donor_forum(G::$LoggedUser['ID'])) { if ($ForumID == DONOR_FORUM && Donations::has_donor_forum(G::$LoggedUser['ID'])) {

View File

@ -93,6 +93,11 @@ public static function get_top_tracks($Username, $Limit = 15) {
return $Response; return $Response;
} }
public static function get_artist_chart($Username, $From = '', $To = '') {
$Response = self::lastfm_request("user.getWeeklyArtistChart", array("user" => $Username));
$Response = json_encode($Response);
}
public static function clear_cache($Username, $Uid) { public static function clear_cache($Username, $Uid) {
$Response = G::$Cache->get_value('lastfm_clear_cache_' . G::$LoggedUser['ID'] . '_' . $_GET['id']); $Response = G::$Cache->get_value('lastfm_clear_cache_' . G::$LoggedUser['ID'] . '_' . $_GET['id']);
if (empty($Response)) { if (empty($Response)) {

View File

@ -77,10 +77,8 @@ public static function get_permissions_for_user($UserID, $CustomPermissions = fa
$BonusPerms = array_merge($BonusPerms, $ClassPerms['Permissions']); $BonusPerms = array_merge($BonusPerms, $ClassPerms['Permissions']);
} }
if (!empty($CustomPermissions)) { if (empty($CustomPermissions)) {
$CustomPerms = $CustomPermissions; $CustomPermissions = array();
} else {
$CustomPerms = array();
} }
// This is legacy donor cruft // This is legacy donor cruft
@ -90,18 +88,20 @@ public static function get_permissions_for_user($UserID, $CustomPermissions = fa
$DonorPerms = array('Permissions' => array()); $DonorPerms = array('Permissions' => array());
} }
$DonorCollages = self::get_personal_collages($UserID, $Permissions['Permissions']['users_mod']); $IsMod = isset($Permissions['Permissions']['users_mod']) && $Permissions['Permissions']['users_mod'];
$DonorCollages = self::get_personal_collages($UserID, $IsMod);
$MaxCollages = $Permissions['Permissions']['MaxCollages'] $MaxCollages = $Permissions['Permissions']['MaxCollages'] + $BonusCollages + $DonorCollages;
+ $BonusCollages
+ $CustomPerms['MaxCollages'] if (isset($CustomPermissions['MaxCollages'])) {
+ $DonorCollages; $MaxCollages += $CustomPermissions['MaxCollages'];
}
//Combine the permissions //Combine the permissions
return array_merge( return array_merge(
$Permissions['Permissions'], $Permissions['Permissions'],
$BonusPerms, $BonusPerms,
$CustomPerms, $CustomPermissions,
$DonorPerms['Permissions'], $DonorPerms['Permissions'],
array('MaxCollages' => $MaxCollages)); array('MaxCollages' => $MaxCollages));
} }

View File

@ -26,7 +26,7 @@ public function __construct($Server, $Port, $Socket) {
$this->Server = $Server; $this->Server = $Server;
$this->Port = $Port; $this->Port = $Port;
$this->Socket = $Socket; $this->Socket = $Socket;
$this->Ident = $this->get_ident($Server, $Port, $Socket); $this->Ident = self::get_ident($Server, $Port, $Socket);
} }
/** /**
@ -37,7 +37,7 @@ public function __construct($Server, $Port, $Socket) {
* @param string $Socket Unix socket address, overrides $Server:$Port * @param string $Socket Unix socket address, overrides $Server:$Port
* @return identification string * @return identification string
*/ */
private function get_ident($Server, $Port, $Socket) { private static function get_ident($Server, $Port, $Socket) {
if ($Socket) { if ($Socket) {
return $Socket; return $Socket;
} else { } else {
@ -64,7 +64,7 @@ public static function init_connection($Server, $Port, $Socket) {
/** /**
* Connect the Sphinxql object to the Sphinx server * Connect the Sphinxql object to the Sphinx server
*/ */
public function sphconnect() { public function sph_connect() {
if ($this->Connected || $this->connect_errno) { if ($this->Connected || $this->connect_errno) {
return; return;
} }
@ -114,7 +114,7 @@ public function error($Msg, $Halt = false) {
* @param string $String string to escape * @param string $String string to escape
* @return escaped string * @return escaped string
*/ */
public function escape_string($String) { public static function sph_escape_string($String) {
return strtr($String, array( return strtr($String, array(
'('=>'\\\\(', '('=>'\\\\(',
')'=>'\\\\)', ')'=>'\\\\)',
@ -141,8 +141,8 @@ public function escape_string($String) {
* @param string $QueryString query text * @param string $QueryString query text
* @param param $QueryProcessTime time building and processing the query * @param param $QueryProcessTime time building and processing the query
*/ */
public function register_query($QueryString, $QueryProcessTime) { public static function register_query($QueryString, $QueryProcessTime) {
Sphinxql::$Queries[] = array($QueryString, $QueryProcessTime); self::$Queries[] = array($QueryString, $QueryProcessTime);
Sphinxql::$Time += $QueryProcessTime; self::$Time += $QueryProcessTime;
} }
} }

View File

@ -116,7 +116,7 @@ public function where_match($Expr, $Field = '*', $Escape = true) {
$Field = "@$Field "; $Field = "@$Field ";
} }
if ($Escape === true) { if ($Escape === true) {
$this->Expressions[] = "$Field".Sphinxql::escape_string($Expr); $this->Expressions[] = "$Field".Sphinxql::sph_escape_string($Expr);
} else { } else {
$this->Expressions[] = $Field.$Expr; $this->Expressions[] = $Field.$Expr;
} }
@ -282,13 +282,15 @@ private function send_query($GetMeta) {
if (!$this->QueryString) { if (!$this->QueryString) {
return false; return false;
} }
$this->Sphinxql->sphconnect(); $this->Sphinxql->sph_connect();
$Result = $this->Sphinxql->query($this->QueryString); $Result = $this->Sphinxql->query($this->QueryString);
if ($Result === false) { if ($Result === false) {
$Errno = $this->Sphinxql->errno; $Errno = $this->Sphinxql->errno;
$Error = $this->Sphinxql->error; $Error = $this->Sphinxql->error;
$this->error("Query returned error $Errno ($Error).\n$this->QueryString"); $this->error("Query returned error $Errno ($Error).\n$this->QueryString");
} else { } else {
$Errno = 0;
$Error = '';
$Meta = $GetMeta ? $this->get_meta() : null; $Meta = $GetMeta ? $this->get_meta() : null;
} }
return new SphinxqlResult($Result, $Meta, $Errno, $Error); return new SphinxqlResult($Result, $Meta, $Errno, $Error);

View File

@ -56,13 +56,17 @@ class Tags {
* E.g., compilations and soundtracks are skipped, so false * E.g., compilations and soundtracks are skipped, so false
*/ */
public function __construct($TagList, $Merge = true) { public function __construct($TagList, $Merge = true) {
$this->Tags = array_filter(explode(' ', str_replace('_', '.', $TagList))); if ($TagList) {
$this->Tags = array_filter(explode(' ', str_replace('_', '.', $TagList)));
if ($Merge) { if ($Merge) {
self::$All = array_merge(self::$All, $this->Tags); self::$All = array_merge(self::$All, $this->Tags);
}
$this->Primary = $this->Tags[0];
} else {
$this->Tags = array();
} }
$this->Primary = $this->Tags[0];
} }
/** /**

View File

@ -631,8 +631,7 @@ public static function show_avatar($Avatar, $UserID, $Username, $Setting, $Size
$ToReturn = ($ReturnHTML ? "<img src=\"$Avatar\" width=\"$Size\" $Style $AvatarMouseOverText $SecondAvatar $Class />" : $Avatar); $ToReturn = ($ReturnHTML ? "<img src=\"$Avatar\" width=\"$Size\" $Style $AvatarMouseOverText $SecondAvatar $Class />" : $Avatar);
} else { } else {
$URL = STATIC_SERVER.'common/avatars/default.png'; $URL = STATIC_SERVER.'common/avatars/default.png';
//TODO: what is the $JS variable for? why is it unassigned? $ToReturn = ($ReturnHTML ? "<img src=\"$URL\" width=\"$Size\" $Style $AvatarMouseOverText $SecondAvatar />" : $URL);
$ToReturn = ($ReturnHTML ? "<img src=\"$URL\" width=\"$Size\" $Style $AvatarMouseOverText $SecondAvatar $JS />" : $URL);
} }
break; break;
case 2: case 2:

View File

@ -41,7 +41,7 @@ public static function show_header($PageTitle = '', $JSIncludes = '', $CSSInclud
* Here is a list of parameters that work in the $Options array: * Here is a list of parameters that work in the $Options array:
* ['disclaimer'] = [boolean] (False) Displays the disclaimer in the footer * ['disclaimer'] = [boolean] (False) Displays the disclaimer in the footer
*/ */
public static function show_footer ($Options = array()) { public static function show_footer($Options = array()) {
global $ScriptStartTime, $SessionID, $UserSessions, $Debug, $Time; global $ScriptStartTime, $SessionID, $UserSessions, $Debug, $Time;
if (!is_array(G::$LoggedUser)) { if (!is_array(G::$LoggedUser)) {
require(SERVER_ROOT.'/design/publicfooter.php'); require(SERVER_ROOT.'/design/publicfooter.php');
@ -65,7 +65,7 @@ public static function show_footer ($Options = array()) {
* @param string $TemplateName The name of the template, in underscore_format * @param string $TemplateName The name of the template, in underscore_format
* @param array $Args the arguments passed to the template. * @param array $Args the arguments passed to the template.
*/ */
public static function render_template ($TemplateName, $Args) { public static function render_template($TemplateName, $Args) {
static $LoadedTemplates; // Keep track of templates we've already loaded. static $LoadedTemplates; // Keep track of templates we've already loaded.
$ClassName = ''; $ClassName = '';
if (isset($LoadedTemplates[$TemplateName])) { if (isset($LoadedTemplates[$TemplateName])) {
@ -113,7 +113,7 @@ public static function render_template ($TemplateName, $Args) {
* echo $SavedTemplate; // Output the buffer * echo $SavedTemplate; // Output the buffer
* </pre> * </pre>
*/ */
public static function parse ($TemplateFile, array $Variables = null, $Buffer = false) { public static function parse($TemplateFile, array $Variables = array(), $Buffer = false) {
$Template = self::IncludePath . $TemplateFile; $Template = self::IncludePath . $TemplateFile;
if (file_exists($Template)) { if (file_exists($Template)) {
extract($Variables); extract($Variables);

View File

@ -1,12 +1,12 @@
INSTALLATION NOTES INSTALLATION NOTES
1. Set up MySQL and memcached. We run memcached with the command: 1. Set up MySQL and memcached. memcached can be started with the command:
memcached -d -m 5120 -s /var/run/memcached.sock -a 0777 -t16 -C -u root memcached -d -m 5120 -s /var/run/memcached.sock -a 0777 -t4 -C -u nobody
This gives it 5 gigs of RAM; you probably want to set that a bit lower! This starts 4 threads and gives it 5 gigs of RAM
2. Run gazelle.sql (preferably as root) to create the database, the table, and the default data. 2. Run gazelle.sql (preferably as root) to create the database, the table, and the default data.
3. Install Sphinx - we recommend you use the included sphinx.conf. You can copy this to 3. Install Sphinx - we recommend you use the included sphinx.conf. You can copy this to
/etc/sphinx/sphinx.conf. You need to fill in the details of the SQL server though! /etc/sphinx/sphinx.conf. You need to fill in the details of the SQL server though!
You might also need to create the /var/data/sphinx folder. You might also need to create the /var/lib/sphinx folder.
For documentation, read http://www.sphinxsearch.com/docs/current.html For documentation, read http://www.sphinxsearch.com/docs/current.html
@ -21,10 +21,10 @@ the peerupdate (all groups are cached, but the peer counts change often,
so peerupdate is a script to update them), and the two Sphinx indices. so peerupdate is a script to update them), and the two Sphinx indices.
These are our cron jobs. SCHEDULE_KEY is the same as in classes/config.php: These are our cron jobs. SCHEDULE_KEY is the same as in classes/config.php:
0,15,30,45 * * * * /usr/local/bin/php /var/www/vhosts/what/schedule.php SCHEDULE_KEY >> /root/schedule.log 0,15,30,45 * * * * /usr/bin/php /var/www/vhosts/what/schedule.php SCHEDULE_KEY >> /root/schedule.log
10,25,40,55 * * * * /usr/local/bin/php /var/www/vhosts/what/peerupdate.php SCHEDULE_KEY >> /root/peerupdate.log 10,25,40,55 * * * * /usr/bin/php /var/www/vhosts/what/peerupdate.php SCHEDULE_KEY >> /root/peerupdate.log
* * * * * /usr/local/bin/indexer -c /etc/sphinx/sphinx.conf --rotate delta * * * * * /usr/bin/indexer -c /etc/sphinx/sphinx.conf --rotate delta requests_delta log_delta >/dev/null
5 0,12 * * * /usr/local/bin/indexer -c /etc/sphinx/sphinx.conf --rotate --all 5 0,12 * * * /usr/bin/indexer -c /etc/sphinx/sphinx.conf --rotate --all >>/root/sphinx-indexer.log
7. You're probably going to want IP geolocation information, so first you need to fill in the geoip_country tables by visiting /tools.php?action=update_geoip 7. You're probably going to want IP geolocation information, so first you need to fill in the geoip_country tables by visiting /tools.php?action=update_geoip
After that finishes parsing information from MaxMind, you may want to map users to countries by running: After that finishes parsing information from MaxMind, you may want to map users to countries by running:

View File

@ -164,7 +164,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
if (!empty($_GET['filelist'])) { if (!empty($_GET['filelist'])) {
$SearchString = trim($_GET['filelist']); $SearchString = trim($_GET['filelist']);
if ($SearchString !== '') { if ($SearchString !== '') {
$SearchString = '"'.Sphinxql::escape_string($_GET['filelist']).'"~20'; $SearchString = '"'.Sphinxql::sph_escape_string($_GET['filelist']).'"~20';
$SphQL->where_match($SearchString, 'filelist', false); $SphQL->where_match($SearchString, 'filelist', false);
$SphQLTor->where_match($SearchString, 'filelist', false); $SphQLTor->where_match($SearchString, 'filelist', false);
$EnableNegation = true; $EnableNegation = true;
@ -244,11 +244,11 @@ function header_link($SortKey, $DefaultWay = 'desc') {
} }
$QueryParts = array(); $QueryParts = array();
foreach ($BasicSearch['include'] as $Word) { foreach ($BasicSearch['include'] as $Word) {
$QueryParts[] = Sphinxql::escape_string($Word); $QueryParts[] = Sphinxql::sph_escape_string($Word);
} }
if (!empty($BasicSearch['exclude'])) { if (!empty($BasicSearch['exclude'])) {
foreach ($BasicSearch['exclude'] as $Word) { foreach ($BasicSearch['exclude'] as $Word) {
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word, 1)); $QueryParts[] = '!'.Sphinxql::sph_escape_string(substr($Word, 1));
} }
} }
if (!empty($FilterBitrates)) { if (!empty($FilterBitrates)) {
@ -280,11 +280,11 @@ function header_link($SortKey, $DefaultWay = 'desc') {
unset($Tags['exclude']); unset($Tags['exclude']);
} }
foreach ($Tags['include'] as &$Tag) { foreach ($Tags['include'] as &$Tag) {
$Tag = Sphinxql::escape_string($Tag); $Tag = Sphinxql::sph_escape_string($Tag);
} }
if (!empty($Tags['exclude'])) { if (!empty($Tags['exclude'])) {
foreach ($Tags['exclude'] as &$Tag) { foreach ($Tags['exclude'] as &$Tag) {
$Tag = '!'.Sphinxql::escape_string(substr($Tag, 1)); $Tag = '!'.Sphinxql::sph_escape_string(substr($Tag, 1));
} }
} }
@ -307,6 +307,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
} }
if (!empty($QueryParts)) { if (!empty($QueryParts)) {
$SphQL->where_match(implode(' ', $QueryParts), 'taglist', false); $SphQL->where_match(implode(' ', $QueryParts), 'taglist', false);
$SphQLTor->where_match(implode(' ', $QueryParts), 'taglist', false);
$Filtered = true; $Filtered = true;
} }
unset($SearchWords['taglist']); unset($SearchWords['taglist']);
@ -321,11 +322,11 @@ function header_link($SortKey, $DefaultWay = 'desc') {
unset($Words['exclude']); unset($Words['exclude']);
} }
foreach ($Words['include'] as $Word) { foreach ($Words['include'] as $Word) {
$QueryParts[] = Sphinxql::escape_string($Word); $QueryParts[] = Sphinxql::sph_escape_string($Word);
} }
if (!empty($Words['exclude'])) { if (!empty($Words['exclude'])) {
foreach ($Words['exclude'] as $Word) { foreach ($Words['exclude'] as $Word) {
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word, 1)); $QueryParts[] = '!'.Sphinxql::sph_escape_string(substr($Word, 1));
} }
} }
if (!empty($QueryParts)) { if (!empty($QueryParts)) {
@ -390,7 +391,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
} }
} }
if (!empty($_GET['freetorrent'])) { if (isset($_GET['freetorrent'])) {
switch ($_GET['freetorrent']) { switch ($_GET['freetorrent']) {
case 0: // Only normal freeleech case 0: // Only normal freeleech
$SphQL->where('freetorrent', 0); $SphQL->where('freetorrent', 0);
@ -677,7 +678,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
'logScore' => (int) $Data['LogScore'], 'logScore' => (int) $Data['LogScore'],
'hasCue' => $Data['HasCue'] == '1', 'hasCue' => $Data['HasCue'] == '1',
'scene' => $Data['Scene'] == '1', 'scene' => $Data['Scene'] == '1',
'vanityHouse' => $Data['VanityHouse'] == '1', 'vanityHouse' => $GroupInfo['VanityHouse'] == '1',
'fileCount' => (int) $Data['FileCount'], 'fileCount' => (int) $Data['FileCount'],
'time' => $Data['Time'], 'time' => $Data['Time'],
'size' => (int) $Data['Size'], 'size' => (int) $Data['Size'],
@ -699,7 +700,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
'cover' => $GroupInfo['WikiImage'], 'cover' => $GroupInfo['WikiImage'],
'tags' => $TagList, 'tags' => $TagList,
'bookmarked' => in_array($GroupID, $Bookmarks), 'bookmarked' => in_array($GroupID, $Bookmarks),
'vanityHouse' => $GroupVanityHouse == '1', 'vanityHouse' => $GroupInfo['VanityHouse'] == '1',
'groupYear' => (int) $GroupYear, 'groupYear' => (int) $GroupYear,
'releaseType' => $ReleaseTypes[$ReleaseType], 'releaseType' => $ReleaseTypes[$ReleaseType],
'groupTime' => (string) $GroupTime, 'groupTime' => (string) $GroupTime,

View File

@ -236,7 +236,7 @@ function compare($X, $Y) {
break; break;
} }
if (!empty($LoggedUser['DiscogView']) || (isset($LoggedUser['SortHide']) && array_key_exists($ReleaseType, $LoggedUser['SortHide']) && $LoggedUser['SortHide'][$ReleaseType] == 1)) { if (!empty($LoggedUser['DiscogView']) || (isset($LoggedUser['SortHide'][$ReleaseID]) && $LoggedUser['SortHide'][$ReleaseID] == 1)) {
$ToggleStr = " onclick=\"$('.releases_$ReleaseID').gshow(); return true;\""; $ToggleStr = " onclick=\"$('.releases_$ReleaseID').gshow(); return true;\"";
} else { } else {
$ToggleStr = ''; $ToggleStr = '';
@ -402,12 +402,14 @@ function compare($X, $Y) {
<? } ?> <? } ?>
<div class="group_info clear"> <div class="group_info clear">
<strong><?=$DisplayName?></strong> <strong><?=$DisplayName?></strong>
<? if (Bookmarks::has_bookmarked('torrent', $GroupID)) { <? if (Bookmarks::has_bookmarked('torrent', $GroupID)) { ?>
echo "<a style=\"float: right;\" href=\"#\" id=\"bookmarklink_torrent_$GroupID\" class=\"remove_bookmark brackets\" onclick=\"Unbookmark('torrent', $GroupID, 'Bookmark'); return false;\">Remove bookmark</a>"; <a style="float: right;" href="#" id="bookmarklink_torrent_<?=$GroupID?>" class="remove_bookmark brackets" onclick="Unbookmark('torrent', <?=$GroupID?>, 'Bookmark'); return false;">Remove bookmark</a>
} else { <? } else { ?>
echo "<a style=\"float: right;\" href=\"#\" id=\"bookmarklink_torrent_$GroupID\" class=\"add_bookmark brackets\" onclick=\"Bookmark('torrent', $GroupID, 'Remove bookmark'); return false;\">Bookmark</a>"; <a style="float: right;" href="#" id="bookmarklink_torrent_<?=$GroupID?>" class="add_bookmark brackets" onclick="Bookmark('torrent', <?=$GroupID?>, 'Remove bookmark'); return false;">Bookmark</a>
} ?> <? }
<?Votes::vote_link($GroupID, $UserVotes[$GroupID]['Type']);?> $VoteType = isset($UserVotes[$GroupID]['Type']) ? $UserVotes[$GroupID]['Type'] : '';
Votes::vote_link($GroupID, $VoteType);
?>
<div class="tags"><?=$TorrentTags->format('torrents.php?taglist=', $Name)?></div> <div class="tags"><?=$TorrentTags->format('torrents.php?taglist=', $Name)?></div>
</div> </div>
</td> </td>
@ -432,7 +434,7 @@ function compare($X, $Y) {
|| $Torrent['RemasterYear'] != $LastRemasterYear || $Torrent['RemasterYear'] != $LastRemasterYear
|| $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel
|| $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber
|| $FirstUnknown || isset($FirstUnknown) && $FirstUnknown
|| $Torrent['Media'] != $LastMedia || $Torrent['Media'] != $LastMedia
) { ) {

View File

@ -148,7 +148,7 @@
$SQL .= " AND CategoryID IN(".db_string(implode(',', $Categories)).')'; $SQL .= " AND CategoryID IN(".db_string(implode(',', $Categories)).')';
} }
if ($_GET['action'] === 'mine') { if (isset($_GET['action']) && $_GET['action'] === 'mine') {
$SQL = $BaseSQL; $SQL = $BaseSQL;
$SQL .= " $SQL .= "
AND c.UserID = '".$LoggedUser['ID']."' AND c.UserID = '".$LoggedUser['ID']."'

View File

@ -70,7 +70,7 @@ function compare($X, $Y) {
WHERE UserID = ".$LoggedUser['ID']." WHERE UserID = ".$LoggedUser['ID']."
AND CollageID = $CollageID"); AND CollageID = $CollageID");
if ($CollageCategoryID == array_search(ARTIST_COLLAGE, $CollageCats)) { if ((int)$CollageCategoryID === array_search(ARTIST_COLLAGE, $CollageCats)) {
include(SERVER_ROOT.'/sections/collages/artist_collage.php'); include(SERVER_ROOT.'/sections/collages/artist_collage.php');
} else { } else {
include(SERVER_ROOT.'/sections/collages/torrent_collage.php'); include(SERVER_ROOT.'/sections/collages/torrent_collage.php');

View File

@ -73,19 +73,15 @@
?> ?>
<ul class="stats nobullet"> <ul class="stats nobullet">
<? <?
if (count($Blog) < 5) { $End = min(count($Blog), 5);
$Limit = count($Blog); for ($i = 0; $i < $End; $i++) {
} else { list($BlogID, $Author, $Title, $Body, $BlogTime) = $Blog[$i];
$Limit = 5;
}
for ($i = 0; $i < $Limit; $i++) {
list($BlogID, $Author, $Title, $Body, $BlogTime, $ThreadID) = $Blog[$i];
$BlogTime = strtotime($BlogTime); $BlogTime = strtotime($BlogTime);
?> ?>
<li> <li>
<?=($SBlogReadTime < $BlogTime) ? '<strong>' : ''?><?=($i + 1)?>. <?=$SBlogReadTime < $BlogTime ? '<strong>' : ''?><?=($i + 1)?>.
<a href="staffblog.php#blog<?=$BlogID?>"><?=$Title?></a> <a href="staffblog.php#blog<?=$BlogID?>"><?=$Title?></a>
<?=($SBlogReadTime < $BlogTime)?'</strong>':''?> <?=$SBlogReadTime < $BlogTime ? '</strong>' : ''?>
</li> </li>
<? <?
} }

View File

@ -28,7 +28,7 @@
</tr> </tr>
<? <?
while (list($UserID, $BitcoinAddress) = $DB->next_record(MYSQLI_NUM, false)) { while (list($UserID, $BitcoinAddress) = $DB->next_record(MYSQLI_NUM, false)) {
if (!$BitcoinAddresses[$BitcoinAddress]) { if (!isset($BitcoinAddresses[$BitcoinAddress])) {
continue; continue;
} }
?> ?>

View File

@ -139,6 +139,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
'sumleechers' => 'SUM(leechers) AS sumleechers', 'sumleechers' => 'SUM(leechers) AS sumleechers',
'sumsnatched' => 'SUM(snatched) AS sumsnatched'); 'sumsnatched' => 'SUM(snatched) AS sumsnatched');
} else { } else {
$GroupResults = false;
$SortOrders = array( $SortOrders = array(
'year' => 'year', 'year' => 'year',
'time' => 'id', 'time' => 'id',
@ -208,7 +209,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
if (!empty($_GET['filelist'])) { if (!empty($_GET['filelist'])) {
$SearchString = trim($_GET['filelist']); $SearchString = trim($_GET['filelist']);
if ($SearchString != '') { if ($SearchString != '') {
$SearchString = '"'.Sphinxql::escape_string($_GET['filelist']).'"~20'; $SearchString = '"'.Sphinxql::sph_escape_string($_GET['filelist']).'"~20';
$SphQL->where_match($SearchString, 'filelist', false); $SphQL->where_match($SearchString, 'filelist', false);
$SphQLTor->where_match($SearchString, 'filelist', false); $SphQLTor->where_match($SearchString, 'filelist', false);
$EnableNegation = true; $EnableNegation = true;
@ -296,11 +297,11 @@ function header_link($SortKey, $DefaultWay = 'desc') {
} }
$QueryParts = array(); $QueryParts = array();
foreach ($BasicSearch['include'] as $Word) { foreach ($BasicSearch['include'] as $Word) {
$QueryParts[] = Sphinxql::escape_string($Word); $QueryParts[] = Sphinxql::sph_escape_string($Word);
} }
if (!empty($BasicSearch['exclude'])) { if (!empty($BasicSearch['exclude'])) {
foreach ($BasicSearch['exclude'] as $Word) { foreach ($BasicSearch['exclude'] as $Word) {
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word, 1)); $QueryParts[] = '!'.Sphinxql::sph_escape_string(substr($Word, 1));
} }
} }
if (!empty($FilterBitrates)) { if (!empty($FilterBitrates)) {
@ -376,11 +377,11 @@ function header_link($SortKey, $DefaultWay = 'desc') {
unset($Tags['exclude']); unset($Tags['exclude']);
} }
foreach ($Tags['include'] as &$Tag) { foreach ($Tags['include'] as &$Tag) {
$Tag = Sphinxql::escape_string($Tag); $Tag = Sphinxql::sph_escape_string($Tag);
} }
if (!empty($Tags['exclude'])) { if (!empty($Tags['exclude'])) {
foreach ($Tags['exclude'] as &$Tag) { foreach ($Tags['exclude'] as &$Tag) {
$Tag = '!'.Sphinxql::escape_string(substr($Tag, 1)); $Tag = '!'.Sphinxql::sph_escape_string(substr($Tag, 1));
} }
} }
@ -405,6 +406,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
} }
if (!empty($QueryParts)) { if (!empty($QueryParts)) {
$SphQL->where_match(implode(' ', $QueryParts), 'taglist', false); $SphQL->where_match(implode(' ', $QueryParts), 'taglist', false);
$SphQLTor->where_match(implode(' ', $QueryParts), 'taglist', false);
$Filtered = true; $Filtered = true;
} }
unset($SearchWords['taglist']); unset($SearchWords['taglist']);
@ -412,6 +414,9 @@ function header_link($SortKey, $DefaultWay = 'desc') {
elseif (!isset($_GET['tags_type'])) { elseif (!isset($_GET['tags_type'])) {
$_GET['tags_type'] = '1'; $_GET['tags_type'] = '1';
} }
if (!isset($TagListString)) {
$TagListString = "";
}
foreach ($SearchWords as $Search => $Words) { foreach ($SearchWords as $Search => $Words) {
$QueryParts = array(); $QueryParts = array();
@ -420,11 +425,11 @@ function header_link($SortKey, $DefaultWay = 'desc') {
unset($Words['exclude']); unset($Words['exclude']);
} }
foreach ($Words['include'] as $Word) { foreach ($Words['include'] as $Word) {
$QueryParts[] = Sphinxql::escape_string($Word); $QueryParts[] = Sphinxql::sph_escape_string($Word);
} }
if (!empty($Words['exclude'])) { if (!empty($Words['exclude'])) {
foreach ($Words['exclude'] as $Word) { foreach ($Words['exclude'] as $Word) {
$QueryParts[] = '!'.Sphinxql::escape_string(substr($Word, 1)); $QueryParts[] = '!'.Sphinxql::sph_escape_string(substr($Word, 1));
} }
} }
if (!empty($QueryParts)) { if (!empty($QueryParts)) {
@ -490,7 +495,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
} }
} }
if (!empty($_GET['freetorrent']) || $_GET['freetorrent'] === '0') { if (isset($_GET['freetorrent'])) {
switch ($_GET['freetorrent']) { switch ($_GET['freetorrent']) {
case 0: // Only normal freeleech case 0: // Only normal freeleech
$SphQL->where('freetorrent', 0); $SphQL->where('freetorrent', 0);
@ -1013,7 +1018,7 @@ function header_link($SortKey, $DefaultWay = 'desc') {
if ($GroupYear > 0) { if ($GroupYear > 0) {
$DisplayName .= " [$GroupYear]"; $DisplayName .= " [$GroupYear]";
} }
if ($GroupVanityHouse) { if ($GroupInfo['VanityHouse']) {
$DisplayName .= ' [<abbr title="This is a Vanity House release">VH</abbr>]'; $DisplayName .= ' [<abbr title="This is a Vanity House release">VH</abbr>]';
} }
$DisplayName .= ' ['.$ReleaseTypes[$ReleaseType].']'; $DisplayName .= ' ['.$ReleaseTypes[$ReleaseType].']';

View File

@ -284,9 +284,9 @@ function compare($X, $Y) {
<? <?
} }
} }
if ((count($Artists[6]) > 0) && (count($Artists[1]) > 0)) { if (!empty($Artists[6]) && !empty($Artists[1])) {
print ' <li class="artists_main"><strong class="artists_label">Artists:</strong></li>'; print ' <li class="artists_main"><strong class="artists_label">Artists:</strong></li>';
} elseif ((count($Artists[4]) > 0) && (count($Artists[1]) > 0)) { } elseif (!empty($Artists[6]) && !empty($Artists[1])) {
print ' <li class="artists_main"><strong class="artists_label">Performers:</strong></li>'; print ' <li class="artists_main"><strong class="artists_label">Performers:</strong></li>';
} }
foreach ($Artists[1] as $Artist) { foreach ($Artists[1] as $Artist) {
@ -630,8 +630,6 @@ function filelist($Str) {
$ExtraInfo = ''; // String that contains information on the torrent (e.g. format and encoding) $ExtraInfo = ''; // String that contains information on the torrent (e.g. format and encoding)
$AddExtra = ''; // Separator between torrent properties $AddExtra = ''; // Separator between torrent properties
$TorrentUploader = $Username; // Save this for "Uploaded by:" below
// similar to Torrents::torrent_info() // similar to Torrents::torrent_info()
if ($Format) { $ExtraInfo.=display_str($Format); $AddExtra=' / '; } if ($Format) { $ExtraInfo.=display_str($Format); $AddExtra=' / '; }
if ($Encoding) { $ExtraInfo.=$AddExtra.display_str($Encoding); $AddExtra=' / '; } if ($Encoding) { $ExtraInfo.=$AddExtra.display_str($Encoding); $AddExtra=' / '; }

View File

@ -3,16 +3,6 @@ function get_group_info($GroupID, $Return = true, $RevisionID = 0, $PersonalProp
global $Cache, $DB; global $Cache, $DB;
if (!$RevisionID) { if (!$RevisionID) {
$TorrentCache = $Cache->get_value("torrents_details_$GroupID"); $TorrentCache = $Cache->get_value("torrents_details_$GroupID");
// This block can be used to test if the cached data predates structure changes
if (isset($TorrentCache[0][0])) {
$OutdatedCache = true;
} else {
$Torrent = current($TorrentCache[1]);
if (!isset($Torrent['InfoHash'])) {
$OutdatedCache = true;
}
}
} }
if ($RevisionID || !is_array($TorrentCache) || isset($OutdatedCache)) { if ($RevisionID || !is_array($TorrentCache) || isset($OutdatedCache)) {
// Fetch the group details // Fetch the group details

View File

@ -80,7 +80,7 @@ function inverse_ncdf($p) {
} }
// Confidence level for binomial scoring. Just compute this once. // Confidence level for binomial scoring. Just compute this once.
define(Z_VAL, inverse_ncdf(1-(1-.95)/2)); define('Z_VAL', inverse_ncdf(1-(1-.95)/2));
// Implementation of the algorithm described at http://www.evanmiller.org/how-not-to-sort-by-average-rating.html // Implementation of the algorithm described at http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
function binomial_score($Ups, $Total) { function binomial_score($Ups, $Total) {

View File

@ -1,11 +1,8 @@
# We use /var/data, because sphinx created it on FreeBSD
# In other distros/operating systems, you may want to use /var/lib/sphinx or /var/lib/sphinxsearch
source connect { source connect {
type = mysql type = mysql
sql_host = localhost sql_host = localhost
sql_port = 3306 sql_port = 3306
sql_sock = /var/run/mysql/mysql.sock sql_sock = /var/run/mysqld/mysqld.sock
sql_user = sql_user =
sql_pass = sql_pass =
sql_db = gazelle sql_db = gazelle
@ -90,12 +87,12 @@ source torrents : torrents_base {
sql_joined_field = artistname from query; \ sql_joined_field = artistname from query; \
select t.id, aname from sphinx_a join sphinx_t t using(gid) order by t.id asc; select t.id, aname from sphinx_a join sphinx_t t using(gid) order by t.id asc;
sql_query_post = delete from sphinx_delta where time<=unix_timestamp(@starttime) sql_query_post_index = delete from sphinx_delta where time<=unix_timestamp(@starttime)
} }
index torrents { index torrents {
source = torrents source = torrents
path = /var/data/sphinx/torrents path = /var/lib/sphinx/torrents
# stopwords = /etc/sphinx/stopwords.txt # Path to file containing a space separated list of words not to index # stopwords = /etc/sphinx/stopwords.txt # Path to file containing a space separated list of words not to index
preopen = 1 preopen = 1
morphology = none morphology = none
@ -306,7 +303,7 @@ source delta : torrents_base {
index delta : torrents { index delta : torrents {
source = delta source = delta
path = /var/data/sphinx/delta path = /var/lib/sphinx/delta
} }
source requests : connect { source requests : connect {
@ -403,11 +400,11 @@ source requests_delta : requests {
} }
index requests : torrents { index requests : torrents {
source = requests source = requests
path = /var/data/sphinx/requests path = /var/lib/sphinx/requests
} }
index requests_delta : requests { index requests_delta : requests {
source = requests_delta source = requests_delta
path = /var/data/sphinx/requests_delta path = /var/lib/sphinx/requests_delta
} }
source log : connect { source log : connect {
@ -424,11 +421,11 @@ source log_delta : log {
index log : torrents { index log : torrents {
source = log source = log
min_word_len = 1 min_word_len = 1
path = /var/data/sphinx/log path = /var/lib/sphinx/log
} }
index log_delta : log { index log_delta : log {
source = log_delta source = log_delta
path = /var/data/sphinx/log_delta path = /var/lib/sphinx/log_delta
} }
source better_transcode : connect { source better_transcode : connect {
@ -458,7 +455,7 @@ source better_transcode : connect {
} }
index better_transcode : torrents { index better_transcode : torrents {
source = better_transcode source = better_transcode
path = /var/data/sphinx/better_transcode path = /var/lib/sphinx/better_transcode
phrase_boundary = phrase_boundary =
} }

View File

@ -0,0 +1,22 @@
$(document).ready(function() {
$('#tiles').imagesLoaded(function() {
$("#tiles img").each(function() {
$(this).height(this.height);
});
// Prepare layout options.
var options = {
container: $('#tiles_container'), // Optional, used for some extra CSS styling
offset: 5, // Optional, the distance between grid items
outerOffset: 10, // Optional, the distance to the containers border
align: 'center',
};
// Get a reference to your grid items.
var handler = $('#tiles li');
// Call the layout function.
handler.wookmark(options);
});
});

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,450 @@
/*!
jQuery Wookmark plugin
@name jquery.wookmark.js
@author Christoph Ono (chri@sto.ph or @gbks)
@author Sebastian Helzle (sebastian@helzle.net or @sebobo)
@version 1.4.3
@date 8/25/2013
@category jQuery plugin
@copyright (c) 2009-2013 Christoph Ono (www.wookmark.com)
@license Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*/
(function (factory) {
if (typeof define === 'function' && define.amd)
define(['jquery'], factory);
else
factory(jQuery);
}(function ($) {
var Wookmark, defaultOptions, __bind;
__bind = function(fn, me) {
return function() {
return fn.apply(me, arguments);
};
};
// Wookmark default options
defaultOptions = {
align: 'center',
autoResize: false,
comparator: null,
container: $('body'),
ignoreInactiveItems: true,
itemWidth: 0,
fillEmptySpace: false,
flexibleWidth: 0,
direction: undefined,
offset: 2,
onLayoutChanged: undefined,
outerOffset: 0,
resizeDelay: 50
};
Wookmark = (function() {
function Wookmark(handler, options) {
// Instance variables.
this.handler = handler;
this.columns = this.containerWidth = this.resizeTimer = null;
this.activeItemCount = 0;
this.itemHeightsDirty = true;
this.placeholders = [];
$.extend(true, this, defaultOptions, options);
// Bind instance methods
this.update = __bind(this.update, this);
this.onResize = __bind(this.onResize, this);
this.onRefresh = __bind(this.onRefresh, this);
this.getItemWidth = __bind(this.getItemWidth, this);
this.layout = __bind(this.layout, this);
this.layoutFull = __bind(this.layoutFull, this);
this.layoutColumns = __bind(this.layoutColumns, this);
this.filter = __bind(this.filter, this);
this.clear = __bind(this.clear, this);
this.getActiveItems = __bind(this.getActiveItems, this);
this.refreshPlaceholders = __bind(this.refreshPlaceholders, this);
this.sortElements = __bind(this.sortElements, this);
// Collect filter data
var i = 0, j = 0, filterClasses = {}, itemFilterClasses, $item, filterClass;
for (; i < handler.length; i++) {
$item = handler.eq(i);
// Read filter classes
itemFilterClasses = $item.data('filterClass');
// Globally store each filter class as object and the fitting items in the array
if (typeof itemFilterClasses == 'object' && itemFilterClasses.length > 0) {
for (j = 0; j < itemFilterClasses.length; j++) {
filterClass = $.trim(itemFilterClasses[j]).toLowerCase();
if (!(filterClass in filterClasses)) {
filterClasses[filterClass] = [];
}
filterClasses[filterClass].push($item[0]);
}
}
}
this.filterClasses = filterClasses;
// Listen to resize event if requested.
if (this.autoResize)
$(window).bind('resize.wookmark', this.onResize);
this.container.bind('refreshWookmark', this.onRefresh);
}
// Method for updating the plugins options
Wookmark.prototype.update = function(options) {
this.itemHeightsDirty = true;
$.extend(true, this, options);
};
// This timer ensures that layout is not continuously called as window is being dragged.
Wookmark.prototype.onResize = function() {
clearTimeout(this.resizeTimer);
this.itemHeightsDirty = this.flexibleWidth !== 0;
this.resizeTimer = setTimeout(this.layout, this.resizeDelay);
};
// Marks the items heights as dirty and does a relayout
Wookmark.prototype.onRefresh = function() {
this.itemHeightsDirty = true;
this.layout();
};
/**
* Filters the active items with the given string filters.
* @param filters array of string
* @param mode 'or' or 'and'
*/
Wookmark.prototype.filter = function(filters, mode) {
var activeFilters = [], activeFiltersLength, activeItems = $(),
i, j, k, filter;
filters = filters || [];
mode = mode || 'or';
if (filters.length) {
// Collect active filters
for (i = 0; i < filters.length; i++) {
filter = $.trim(filters[i].toLowerCase());
if (filter in this.filterClasses) {
activeFilters.push(this.filterClasses[filter]);
}
}
// Get items for active filters with the selected mode
activeFiltersLength = activeFilters.length;
if (mode == 'or' || activeFiltersLength == 1) {
// Set all items in all active filters active
for (i = 0; i < activeFiltersLength; i++) {
activeItems = activeItems.add(activeFilters[i]);
}
} else if (mode == 'and') {
var shortestFilter = activeFilters[0],
itemValid = true, foundInFilter,
currentItem, currentFilter;
// Find shortest filter class
for (i = 1; i < activeFiltersLength; i++) {
if (activeFilters[i].length < shortestFilter.length) {
shortestFilter = activeFilters[i];
}
}
// Iterate over shortest filter and find elements in other filter classes
for (i = 0; i < shortestFilter.length; i++) {
currentItem = shortestFilter[i];
itemValid = true;
for (j = 0; j < activeFilters.length && itemValid; j++) {
currentFilter = activeFilters[j];
if (shortestFilter == currentFilter) continue;
// Search for current item in each active filter class
for (k = 0, foundInFilter = false; k < currentFilter.length && !foundInFilter; k++) {
foundInFilter = currentFilter[k] == currentItem;
}
itemValid &= foundInFilter;
}
if (itemValid)
activeItems.push(shortestFilter[i]);
}
}
// Hide inactive items
this.handler.not(activeItems).addClass('inactive');
} else {
// Show all items if no filter is selected
activeItems = this.handler;
}
// Show active items
activeItems.removeClass('inactive');
// Unset columns and refresh grid for a full layout
this.columns = null;
this.layout();
};
/**
* Creates or updates existing placeholders to create columns of even height
*/
Wookmark.prototype.refreshPlaceholders = function(columnWidth, sideOffset) {
var i = this.placeholders.length,
$placeholder, $lastColumnItem,
columnsLength = this.columns.length, column,
height, top, innerOffset,
containerHeight = this.container.innerHeight();
for (; i < columnsLength; i++) {
$placeholder = $('<div class="wookmark-placeholder"/>').appendTo(this.container);
this.placeholders.push($placeholder);
}
innerOffset = this.offset + parseInt(this.placeholders[0].css('borderWidth'), 10) * 2;
for (i = 0; i < this.placeholders.length; i++) {
$placeholder = this.placeholders[i];
column = this.columns[i];
if (i >= columnsLength || !column[column.length - 1]) {
$placeholder.css('display', 'none');
} else {
$lastColumnItem = column[column.length - 1];
if (!$lastColumnItem) continue;
top = $lastColumnItem.data('wookmark-top') + $lastColumnItem.data('wookmark-height') + this.offset;
height = containerHeight - top - innerOffset;
$placeholder.css({
position: 'absolute',
display: height > 0 ? 'block' : 'none',
left: i * columnWidth + sideOffset,
top: top,
width: columnWidth - innerOffset,
height: height
});
}
}
};
// Method the get active items which are not disabled and visible
Wookmark.prototype.getActiveItems = function() {
return this.ignoreInactiveItems ? this.handler.not('.inactive') : this.handler;
};
// Method to get the standard item width
Wookmark.prototype.getItemWidth = function() {
var itemWidth = this.itemWidth,
innerWidth = this.container.width() - 2 * this.outerOffset,
firstElement = this.handler.eq(0),
flexibleWidth = this.flexibleWidth;
if (this.itemWidth === undefined || this.itemWidth === 0 && !this.flexibleWidth) {
itemWidth = firstElement.outerWidth();
}
else if (typeof this.itemWidth == 'string' && this.itemWidth.indexOf('%') >= 0) {
itemWidth = parseFloat(this.itemWidth) / 100 * innerWidth;
}
// Calculate flexible item width if option is set
if (flexibleWidth) {
if (typeof flexibleWidth == 'string' && flexibleWidth.indexOf('%') >= 0) {
flexibleWidth = parseFloat(flexibleWidth) / 100 * innerWidth;
}
var columns = ~~(0.5 + (innerWidth + this.offset) / (flexibleWidth + this.offset)),
columnWidth = Math.min(flexibleWidth, ~~((innerWidth - (columns - 1) * this.offset) / columns));
itemWidth = Math.max(itemWidth, columnWidth);
// Stretch items to fill calculated width
this.handler.css('width', itemWidth);
}
return itemWidth;
};
// Main layout method.
Wookmark.prototype.layout = function(force) {
// Do nothing if container isn't visible
if (!this.container.is(':visible')) return;
// Calculate basic layout parameters.
var columnWidth = this.getItemWidth() + this.offset,
containerWidth = this.container.width(),
innerWidth = containerWidth - 2 * this.outerOffset,
columns = ~~((innerWidth + this.offset) / columnWidth),
offset = 0, maxHeight = 0, i = 0,
activeItems = this.getActiveItems(),
activeItemsLength = activeItems.length,
$item;
// Cache item height
if (this.itemHeightsDirty) {
for (; i < activeItemsLength; i++) {
$item = activeItems.eq(i);
$item.data('wookmark-height', $item.outerHeight());
}
this.itemHeightsDirty = false;
}
// Use less columns if there are to few items
columns = Math.max(1, Math.min(columns, activeItemsLength));
// Calculate the offset based on the alignment of columns to the parent container
offset = this.outerOffset;
if (this.align == 'center') {
offset += ~~(0.5 + (innerWidth - (columns * columnWidth - this.offset)) >> 1);
}
// Get direction for positioning
this.direction = this.direction || (this.align == 'right' ? 'right' : 'left');
// If container and column count hasn't changed, we can only update the columns.
if (!force && this.columns !== null && this.columns.length == columns && this.activeItemCount == activeItemsLength) {
maxHeight = this.layoutColumns(columnWidth, offset);
} else {
maxHeight = this.layoutFull(columnWidth, columns, offset);
}
this.activeItemCount = activeItemsLength;
// Set container height to height of the grid.
this.container.css('height', maxHeight);
// Update placeholders
if (this.fillEmptySpace) {
this.refreshPlaceholders(columnWidth, offset);
}
if (this.onLayoutChanged !== undefined && typeof this.onLayoutChanged === 'function') {
this.onLayoutChanged();
}
};
/**
* Sort elements with configurable comparator
*/
Wookmark.prototype.sortElements = function(elements) {
return typeof(this.comparator) === 'function' ? elements.sort(this.comparator) : elements;
};
/**
* Perform a full layout update.
*/
Wookmark.prototype.layoutFull = function(columnWidth, columns, offset) {
var $item, i = 0, k = 0,
activeItems = $.makeArray(this.getActiveItems()),
length = activeItems.length,
shortest = null, shortestIndex = null,
itemCSS = {position: 'absolute'},
sideOffset, heights = [],
leftAligned = this.align == 'left' ? true : false;
this.columns = [];
// Sort elements before layouting
activeItems = this.sortElements(activeItems);
// Prepare arrays to store height of columns and items.
while (heights.length < columns) {
heights.push(this.outerOffset);
this.columns.push([]);
}
// Loop over items.
for (; i < length; i++ ) {
$item = $(activeItems[i]);
// Find the shortest column.
shortest = heights[0];
shortestIndex = 0;
for (k = 0; k < columns; k++) {
if (heights[k] < shortest) {
shortest = heights[k];
shortestIndex = k;
}
}
// stick to left side if alignment is left and this is the first column
sideOffset = offset;
if (shortestIndex > 0 || !leftAligned)
sideOffset += shortestIndex * columnWidth;
// Position the item.
itemCSS[this.direction] = sideOffset;
itemCSS.top = shortest;
$item.css(itemCSS).data('wookmark-top', shortest);
// Update column height and store item in shortest column
heights[shortestIndex] += $item.data('wookmark-height') + this.offset;
this.columns[shortestIndex].push($item);
}
// Return longest column
return Math.max.apply(Math, heights);
};
/**
* This layout method only updates the vertical position of the
* existing column assignments.
*/
Wookmark.prototype.layoutColumns = function(columnWidth, offset) {
var heights = [],
i = 0, k = 0, currentHeight,
column, $item, itemCSS, sideOffset;
for (; i < this.columns.length; i++) {
heights.push(this.outerOffset);
column = this.columns[i];
sideOffset = i * columnWidth + offset;
currentHeight = heights[i];
for (k = 0; k < column.length; k++) {
$item = column[k];
itemCSS = {
top: currentHeight
};
itemCSS[this.direction] = sideOffset;
$item.css(itemCSS).data('wookmark-top', currentHeight);
currentHeight += $item.data('wookmark-height') + this.offset;
}
heights[i] = currentHeight;
}
// Return longest column
return Math.max.apply(Math, heights);
};
/**
* Clear event listeners and time outs.
*/
Wookmark.prototype.clear = function() {
clearTimeout(this.resizeTimer);
$(window).unbind('resize.wookmark', this.onResize);
this.container.unbind('refreshWookmark', this.onRefresh);
};
return Wookmark;
})();
$.fn.wookmark = function(options) {
// Create a wookmark instance if not available
if (!this.wookmarkInstance) {
this.wookmarkInstance = new Wookmark(this, options || {});
} else {
this.wookmarkInstance.update(options || {});
}
// Apply layout
this.wookmarkInstance.layout(true);
// Display items (if hidden) and return jQuery object to maintain chainability
return this.show();
};
}));

View File

@ -0,0 +1,58 @@
#tiles_container {
position: relative;
}
/**
* Grid container
*/
#tiles {
list-style-type: none;
position: relative; /** Needed to ensure items are laid out relative to this container **/
margin: 0;
padding: 0;
}
/**
* Grid items
*/
#tiles li {
background-color: #ffffff;
border: 1px solid #dedede;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
display: none; /** Hide items initially to avoid a flicker effect **/
cursor: pointer;
padding: 4px;
}
#tiles li.inactive {
visibility: hidden;
opacity: 0;
}
#tiles li img {
display: block;
}
/**
* Grid item text
*/
#tiles li p {
color: #666;
font-size: 12px;
margin: 7px 0 0 7px;
}
/**
* Placerholder css
*/
.wookmark-placeholder {
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
background-color: #eee;
border: 1px solid #dedede;
z-index: -1;
}