// v0.1 Initial public release // v0.11 Added !category support // v0.12 Added textpos option (thanks lee) and imageid option (thanks wouaren) // v0.2 js and css can now be loaded elsewhere (thanks jstubbs). Added wraptag and changed defaults to make output less like tag-soup (thanks wouaren) // v0.21 Added orderby="fixed" to allowed fixed imageid ordering (thanks lee). $where warning squashed (thanks benjibot) // v0.22 Now uses smd_lib and subcats. Also MLP(Multi-lingual)-aware. // v0.23 Fixed orderby when using random (thanks mrdale) and added ability to override maxlimit // v0.24 Added libcheck (thanks papuass). Numeric ranges now allowed for IDs (smd_lib). Fixed empty field/imageid negation bugs. Fixed next/prev buttons for MLP. // v0.24b Fixed paging in subdirectory installations (thanks ultramega and Qwest) // v0.25 Extended groupname (thanks [Axel]) // v0.25a Bundled latest version of slimbox in the package. Made the docs easier to read. // v0.26 Added true multiple gallery support (thanks wheaticus) // v0.27 Added thumb (thanks progre55) // v0.28 Added imagecaption (thanks Adam_V) // v0.29 Added thumbsize (thanks Simanek) // v0.29a Fixed undefined index warnings (thanks Ambitiouslemon) // v0.29b Fixed the fix from v0.24 regarding an SQL error if the category is not set when using ?c (thanks Mr.Smith). Also fixed 'px' in thumbsize (thanks robin746) // v0.210 Uses smd_lib v0.3. Integer ranges now only allowed in imageid. Added thumbtext/thumbtextclass/paramdelim. Deprecated showalt/showcaption/altclass/captionclass/textpos // v0.211 Fixed (more) undefined index warnings and added onchange text support (thanks karl.spencer, decoderltd). thumbtext can now take (encoded) rudimentary html tags // v0.3 Uses smd_lib v0.31. Added trigger, class and linkclass, deprecated smd_slimbox_inc, removed libcheck and the deprecated atts from v0.210. Moonbox, Imagebox and Thickbox (jQuery) now supported // DEPRECATED function smd_slimbox_inc($atts) { global $production_status; if (in_array($production_status, array('debug', 'testing'))) { trigger_error("smd_slimbox_inc is no longer necessary. Please remove it from your page."); } return; } function smd_slimbox($atts) { require_plugin('smd_lib'); // MLP support global $pretext, $thisarticle, $img_dir, $smd_sboxLang; $smd_sboxStr = array( 'next_lbl' => 'Next', 'prev_lbl' => 'Prev', ); $smd_sboxLang = new smd_MLP('smd_slimbox', 'smd_sbox', $smd_sboxStr); // ** LOOKUP TABLES // Holds database field as key index and plugin option names as value. // Use array_search to find if value exists and return correct key for use in db calls. $fieldMap = array( "name" => "name", "id" => "id", "alt" => "alt", "caption" => "caption", "category" => "category", "author" => "author", "date" => "date", "ext" => "ext", "w" => "width", "h" => "height", ); $showLocs = array("below","above","after","before","onchange"); $classTypes = array_merge(array("group","cell","link","img","thumbtext","nav","prev","next"),$showLocs); $frequencies = array("pos", "step", "when", "even", "odd"); $operands = array("changes", "contains", "eq", "lt", "gt", "lte", "gte", "not"); $thumbholder = "::SBOX_REPL::"; $catidopts = (isset($atts['category']) || isset($atts['imageid'])) ? true : false; // Plugin options extract(lAtts(array( 'paramdelim' => ':', 'imageid' => '', 'category' => '', 'subcats' => false, 'catlabel' => 'article-', 'trigger' => 'lightbox', 'groupname' => 'smd', 'thumb' => false, 'limit' => '0', 'maxlimit' => '99999', 'orderby' => 'category', 'showpagelinks' => '1', 'galleryid' => '?4:6', 'imagecaption' => '?caption', 'thumbtext' => '', 'thumbsize' => '', 'prevlabel' => $smd_sboxLang->gTxt('prev_lbl'), 'nextlabel' => $smd_sboxLang->gTxt('next_lbl'), 'wraptag' => '', 'class' => '', 'appendclasses' => false, 'groupclass' => '', // shortcut for class="group:" 'cellclass' => '', // shortcut for class="cell:" 'linkclass' => '', // shortcut for class="link:" 'imgclass' => '', // shortcut for class="img:" 'navclass' => '', // shortcut for class="nav:" 'prevclass' => 'smd_slimbox_prev', // shortcut for class="prev:" 'nextclass' => 'smd_slimbox_next', // shortcut for class="next:" 'thumbtextclass' => '', // shortcut for class="thumbtext:" 'belowclass' => '', // shortcut for class="below:" 'aboveclass' => '', // shortcut for class="above:" 'afterclass' => '', // shortcut for class="after:" 'beforeclass' => '', // shortcut for class="before:" 'onchangeclass' => '', // shortcut for class="onchange:" ), $atts)); // Category relies on whether imageid has been specified or not. // lAtts() won't let us handle this logic so it has to be done manually $category = isset($category) ? doSlash($category) : (($imageid=="") ? $pretext['c']: ''); $fixedOrder = false; // Main code body // $freqTable = new smd_freqStore($appendclasses); // $freqTable.addType(array("fixed","cyclic","match")); // The trigger is the first part of rel= attribute (before groupname) // ToDo: experiment: add option to suppress trigger and use jQuery to add the rel= attributes when a single thumb/text // link is used to "launch" the gallery (http://forum.textpattern.com/viewtopic.php?pid=146188#p146188) $trigger .= ($trigger) ? "-" : ""; // The gallery identifier is used for keeping track of next/prev thumbpage links $gallID = ""; if ($galleryid == "" || substr($galleryid,0,1) == "?") { // Generate a (hopefully) unique ID for this gallery instance $gallTmp = md5($category.$imageid.$orderby.$limit.$maxlimit.$wraptag); list($gallLen, $gallSkip) = explode(":", substr($galleryid,1)); $gallLen = (empty($gallLen)) ? "4" : $gallLen; $gallSkip = (empty($gallSkip)) ? "1" : $gallSkip; for ($idx = 0, $cnt = 0; $cnt < $gallLen; $cnt++, $idx = (($idx+$gallSkip) % strlen($gallTmp))) { $gallID .= $gallTmp[$idx]; } } else { $gallID = $galleryid; } // Load the class position arrays with relevant info foreach ($classTypes as $type) { $fullclass = ${$type.'class'}; if ($fullclass != "") { $classdefs = smd_split($fullclass, false, ";"); foreach ($classdefs as $classdef) { $classfreqs = smd_split($classdef, false, "@"); $classname = $classfreqs[0]; if (count($classfreqs) > 1) { $frequency = smd_split($classfreqs[1], true, "="); $freq = (in_array($frequency[0], $frequencies)) ? $frequency[0] : ''; if (count($frequency) > 1) { $positions = smd_split($frequency[1], true, "|"); } else { $positions = array(); } // TODO: Handle field names with ? and ! switch ($freq) { case "pos": foreach ($positions as $pos) { $fixedPos[$type][$pos][] = $classname; } break; case "even": $cyclePos[$type][] = '2,0,'.$classname; break; case "odd": $cyclePos[$type][] = '2,1,'.$classname; break; case "step": foreach ($positions as $pos) { $stepoffs = smd_split($pos, true, "+"); $step = $stepoffs[0]; $offset = (count($stepoffs) > 1) ? $stepoffs[1] : 0; $cyclePos[$type][] = $step . ',' . $offset . ',' .$classname; } break; } } else { } } } } dmp($fixedPos); dmp($cyclePos); // Convert the category (possibly a comma-sep list) into an SQL-style 'in' list. $fullCatList = array(); $notCatList = array(); $catVars = array("?c", "!c", "?s", "!s", "?t", "!t", "?id", "!id", "?field", "!field"); list($fullCatList,$notCatList) = smd_getOpts($category, $catVars, $catlabel, false); // Ditto with imageid, except ranges are allowed $fullIDList = array(); $notIDList = array(); $idVars = array("?id", "!id", "?field", "!field"); list($fullIDList,$notIDList) = smd_getOpts($imageid, $idVars); // Make up the WHERE statement from the combined lists. // The categories/image IDs are ORed together in brackets first // before the negation options are tacked on as ANDs afterwards $whereOR = array(); $whereAND = array(); // Start the WHERE statement with the combined list of image IDs if (count($fullIDList) > 0) { for ($idx = count($fullIDList); $idx >=0; $idx--) { if (empty($fullIDList[$idx])) { unset($fullIDList[$idx]); } else { $fullIDList[$idx] = "'" . $fullIDList[$idx] . "'"; } } if (count($fullIDList) > 0) { $whereOR[] = "id IN (" . implode(",", $fullIDList). ")"; } } // included categories - some may be subcats $tmpa = array(); for ($idx = 0; $idx < count($fullCatList); $idx++) { if ($subcats) { $categs = getTree($fullCatList[$idx],'image'); for ($jdx = 0; $jdx < count($categs); $jdx++) { $tmpa[] = "'" .$categs[$jdx]['name']. "'"; } } else { $tmpa[] = "'" .$fullCatList[$idx]. "'"; } } if (count($tmpa) > 0) { $whereOR[] = "category IN (" .implode(",", $tmpa). ")"; } if (count($whereOR) > 0) { $where = "(" . implode(" OR ", $whereOR) . ")"; } else { $where = ""; } // excluded categories $tmpa = array(); for ($idx = 0; $idx < count($notCatList); $idx++) { if ($subcats) { $categs = getTree($notCatList[$idx],'image'); for ($jdx = 0; $jdx < count($categs); $jdx++) { $tmpa[] = "'" .$categs[$jdx]['name']. "'"; } } else { $tmpa[] = "'" .$notCatList[$idx]. "'"; } } if (count($tmpa) > 0) { $whereAND[] = "category NOT IN (" .implode(",", $tmpa). ")"; } // Add to the WHERE statement the combined list of NOT image IDs if (count($notIDList) > 0) { for ($idx = count($notIDList); $idx >=0; $idx--) { if (empty($notIDList[$idx])) { unset($notIDList[$idx]); } else { $notIDList[$idx] = "'" . $notIDList[$idx] . "'"; } } if (count($notIDList) > 0) { $whereAND[] = "id NOT IN (" . implode(",", $notIDList). ")"; } } if (count($whereAND) > 0) { $where .= (($where=="") ? "" : " AND ") . implode(" AND ", $whereAND); } if ($where == "") { if (!$catidopts) { // If no category/id options given, choose from the whole database $where = "1=1"; } else { // If a category/id option was chosen then the values must be empty. // In this case the plugin should choose from a bogus category that should not exist. $where = "category='smd_".mt_rand()."'"; } } // Convert the orderby into a valid sorting hierarchy. // Note that random is a special case and the following rules apply: // 1) Anything appearing before random is passed to the database query for ordering // 2) As soon as random is encountered, the orderby string is ignored. // The resultset will be sorted randomly instead // 3) If random appears first in the list, the data is retrieved randomly then the // remaining options sort the resultset $whereOB = Array(); $postOrder = array(); $rule = "sql"; $postPrefix = "SORT_"; $randsort = false; $obList = preg_split('/[,\s]+/',$orderby,-1,PREG_SPLIT_NO_EMPTY); for ($idx = 0; $idx < count($obList); $idx++) { $ob_dir = explode(':',$obList[$idx]); $direction = ''; $colRef = ''; if (count($ob_dir) <= 1) { $ob_dir[1] = "asc"; } if ($rule == "sql") { $direction = ($ob_dir[1] == "desc") ? ' desc' : ' asc'; } else { $direction = ($ob_dir[1] == "desc") ? $postPrefix.'DESC' : $postPrefix.'ASC'; } switch ($ob_dir[0]) { case 'random': $rule = "post"; if ($idx == 0) { $whereOB[] = 'rand()'; } else { $randsort = true; } break; case 'fixed': // 'fixed' only works on image ids if ($imageid != "") { $fixedOrder = true; } break; default: $colRef = array_search($ob_dir[0], $fieldMap); break; } if ($rule == "sql") { if ($colRef != "") { $whereOB[] = $colRef.$direction; } } else { if (!$randsort) { if ($colRef != "") { $postOrder[] = array("col" => $colRef, "sort" => $direction); } } } } if (count($whereOB) > 0) { $where .= ' ORDER BY ' . implode(",",$whereOB); } // The database fields required $fields = implode(",", array_keys($fieldMap)); // Handle paging if (($limit > 0) && $showpagelinks) { $rs = safe_rows($fields, 'txp_image', $where .' LIMIT 0,'.$maxlimit); $numthum = count($rs); $numPages = ($numthum > 0) ? ceil($numthum/$limit) : 1; $thumbpage = (!gps($gallID)) ? 1 : gps($gallID); $offset = ($thumbpage - 1) * $limit; $rs = safe_rows($fields, 'txp_image', $where .' LIMIT '.$offset.','.$limit); } else { // No paging required $numPages = 1; $thumbpage = 1; $rs = safe_rows($fields, 'txp_image', $where .' LIMIT 0,'. (($limit==0) ? $maxlimit : $limit)); } // Is post-ordering required? Do it if ($randsort) { shuffle($rs); } else if (count($postOrder) > 0) { // Translate the rows into columns that can be sorted foreach($rs as $key => $row) { $col_id[$key] = $row['id']; $col_name[$key] = $row['name']; $col_caption[$key] = $row['caption']; $col_alt[$key] = $row['alt']; $col_category[$key] = $row['category']; $col_date[$key] = $row['date']; $col_ext[$key] = $row['ext']; $col_author[$key] = $row['author']; $col_w[$key] = $row['w']; $col_h[$key] = $row['h']; } // Make up an array_multisort arg list and execute it for ($idx = 0; $idx < count($postOrder); $idx++) { $sortargs[] = '$col_'.$postOrder[$idx]['col']; $sortargs[] = $postOrder[$idx]['sort']; } $sortit = 'array_multisort('.implode(", ",$sortargs).', $rs);'; eval($sortit); } // Is fixed-order output desired? If so, re-order the $rs if ($fixedOrder) { $orderedRS = Array(); $ignoreList = Array(); $remainingRS = Array(); // Suck out the fixed items first for ($idx = 0; $idx < count($fullIDList); $idx++) { foreach($rs as $row) { if ("'".$row['id']."'" == $fullIDList[$idx]) { $orderedRS[] = $row; $ignoreList[] = $row['id']; } } } // Tack on the remaining rows foreach($rs as $row) { if (!in_array($row['id'], $ignoreList)) { $remainingRS[] = $row; } } $rs = array_merge($orderedRS, $remainingRS); } // Handle thumbsize $thumbWidth = $thumbHeight = ""; $thumbWUnits = $thumbHUnits = ""; if ($thumbsize) { $thumbSizes = smd_split(trim($thumbsize), false, ",\s", 0); if (count($thumbSizes) == 1) { $thumbWidth = $thumbHeight = ereg_replace("[^0-9]", "", $thumbSizes[0]); $units = ereg_replace("[0-9]", "", $thumbSizes[0]); $thumbWUnits = $thumbHUnits = ($units == "") ? $thumbWUnits : $units; } else { $thumbWidth = ereg_replace("[^0-9]", "", $thumbSizes[0]); $thumbHeight = ereg_replace("[^0-9]", "", $thumbSizes[1]); $units = ereg_replace("[0-9]", "", $thumbSizes[0]); $thumbWUnits = ($units == "" && $thumbWidth != "") ? $thumbWUnits : $units; $units = ereg_replace("[0-9]", "", $thumbSizes[1]); $thumbHUnits = ($units == "" && $thumbHeight != "") ? $thumbHUnits : $units; } } // Prepare the additional text details to show, if required $showopts = smd_split($thumbtext, false, "/,|,s/"); $posArray = array(); foreach ($showopts as $item) { $showpos = smd_split($item, false, "/".$paramdelim."/"); if (count($showpos) > 1 && in_array($showpos[0],$showLocs)) { $posArray[$showpos[0]] = explode(" ", $showpos[1]); } else { $posArray[$showLocs[0]] = explode(" ", ((count($showpos)>1) ? $showpos[1] : $showpos[0])); } } // Create the class replacement lookups $classDefs = smd_split($class, false); foreach ($classDefs as $classDef) { $classObjs = smd_split($classDef, false, ":"); $validObj = false; for ($idx = 0; $idx < count($classObjs); $idx++) { if ($idx == 0) { // First item is the object to apply the class to $validObj = (in_array($classObjs[0], $classTypes)) ? true : false; } else if ($validObj) { $classFreqs = smd_split($classObjs[$idx], true, "@"); if (count($classFreqs) > 0) { foreach ($classFreqs as $classFreq) { } } else { // cyclic frequency: note that a class applied to every element is cyclic (a cycle length of 1!) $classCycle = smd_split($classObjs[$idx], true, ";"); } } } } // Construct the output $captionItems = smd_split($imagecaption, false, "\s"); $thumbtextPlate = ''.$thumbholder.''; $outStr = ''; if($rs) { $ctr = 1; $thumbtextCurr=""; foreach($rs as $row) { $row['ctr'] = $ctr++; // Add a 'static' counter to the array $theThumb = hu.$img_dir.'/' . $row['id'] . 't' . $row['ext']; $full = hu.$img_dir.'/' . $row['id'] . (($thumb) ? "t" : "") .$row['ext']; if ($groupname === "?c") { $grp = $row['category']; } else if (substr($groupname,0,1) === "?") { // Split off the field name from the question mark $fieldname = substr($groupname,1); // Is it a standard image field? If not, see if it is an article field $grpID = array_search($fieldname, $fieldMap); if ($grpID === false) { if (isset($thisarticle[$fieldname])) { $grp = $thisarticle[$fieldname]; } else { $grp = ''; } } else { $grp = $row[$grpID]; } } else { $grp = $groupname; } // Handle imagecaption $captionArray = array(); foreach ($captionItems as $item) { if (substr($item,0,1) === "?") { $fieldname = substr($item,1); $key = array_search($fieldname, $fieldMap); if ($key) { $captionArray[] = $row[$key]; } else { $captionArray[] = $fieldname; } } else { $captionArray[] = $item; } } // Handle thumbtext $thumbtextArray = array_combine($showLocs, array("","","","","")); // Initialise every element foreach ($posArray as $pos => $text) { foreach ($text as $item) { if (substr($item,0,1) === "?") { $fieldname = substr($item,1); $key = array_search($fieldname, $fieldMap); if ($key) { $thumbtextArray[$pos][] = $row[$key]; } else { $thumbtextArray[$pos][] = $fieldname; } } else { $thumbtextArray[$pos][] = $item; } } $thumbtextArray[$pos] = implode(" ", $thumbtextArray[$pos]); } // Construct the link and put thumbtext in the appropriate position $outStr .= ($thumbtextArray["onchange"] && $thumbtextArray["onchange"] != $thumbtextCurr) ? str_replace($thumbholder, htmlspecialchars_decode($thumbtextArray["onchange"]), $thumbtextPlate) : ''; $outStr .= ($wraptag != "") ? '<' .$wraptag. (($cellclass != "") ? ' class="' .$cellclass. '"' : '') . '>' : ''; $outStr .= ($thumbtextArray["above"]) ? str_replace($thumbholder, htmlspecialchars_decode($thumbtextArray["above"]), $thumbtextPlate) : ''; $outStr .= '' .(($thumbtextArray["before"]) ? str_replace($thumbholder, htmlspecialchars_decode($thumbtextArray["before"]), $thumbtextPlate) : ''). '' .$row['alt']. '' .(($thumbtextArray["after"]) ? str_replace($thumbholder, htmlspecialchars_decode($thumbtextArray["after"]), $thumbtextPlate) : ''). ''.n; $outStr .= ($thumbtextArray["below"]) ? str_replace($thumbholder, htmlspecialchars_decode($thumbtextArray["below"]), $thumbtextPlate) : ''; $outStr .= ($wraptag != "") ? '' : ''; $outStr .= n; $thumbtextCurr = $thumbtextArray["onchange"]; } // Add the paging features if required if (($limit > 0) && $showpagelinks) { $next = ($numPages > 1 && $thumbpage != $numPages); $prev = ($numPages > 1 && $thumbpage > 1); // Replace any paging info in the query string $prevPage = smd_addQSVar($pretext['request_uri'], $gallID, $thumbpage-1); $nextPage = smd_addQSVar($pretext['request_uri'], $gallID, $thumbpage+1); $outStr .= ($wraptag != "") ? '<' .$wraptag. (($navclass != "") ? ' class="' .$navclass. '"' : '') . '>' : ''; $outStr .= ($prev) ? '' .$prevlabel. ''.n : ''; $outStr .= ($next) ? '' .$nextlabel. ''.n : ''; $outStr .= ($wraptag != "") ? '' : ''; $outStr .= n; } } return $outStr; }