Merge branch 'develop' of git://github.com/shish/shimmie2

This commit is contained in:
jgen 2014-02-23 03:11:09 -05:00
commit cebc197fba
57 changed files with 744 additions and 1224 deletions

View File

@ -44,7 +44,6 @@ class BaseThemelet {
$h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip());
$h_tags = strtolower($image->get_tag_list());
$base = get_base_href();
$ext = strtolower($image->ext);
// If the file doesn't support thumbnail generation, show it at max size.
@ -55,7 +54,13 @@ class BaseThemelet {
$tsize = get_thumbnail_size($image->width, $image->height);
}
return "<a href='$h_view_link' class='thumb shm-thumb shm-thumb-link' data-tags='$h_tags' data-post-id='$i_id'>".
$custom_classes = "";
if(class_exists("Relationships")){
if($image->parent_id !== NULL){ $custom_classes .= "shm-thumb-has_parent "; }
if($image->has_children == TRUE){ $custom_classes .= "shm-thumb-has_child "; }
}
return "<a href='$h_view_link' class='thumb shm-thumb shm-thumb-link {$custom_classes}' data-tags='$h_tags' data-post-id='$i_id'>".
"<img id='thumb_$i_id' title='$h_tip' alt='$h_tip' height='{$tsize[1]}' width='{$tsize[0]}' src='$h_thumb_link'>".
"</a>\n";
}
@ -86,7 +91,7 @@ class BaseThemelet {
private function build_paginator($current_page, $total_pages, $base_url, $query) {
$next = $current_page + 1;
$prev = $current_page - 1;
$rand = rand(1, $total_pages);
$rand = mt_rand(1, $total_pages);
$at_start = ($current_page <= 1 || $total_pages <= 1);
$at_end = ($current_page >= $total_pages);

View File

@ -479,15 +479,9 @@ class Image {
$this->delete_tags_from_image();
// insert each new tags
foreach($tags as $tag) {
if(preg_match("/^source[=|:](.*)$/i", $tag, $matches)) {
$this->set_source($matches[1]);
continue;
}
if(preg_match("/^pool[=|:](.*)$/i", $tag, $matches)) {
if(class_exists("Pools")) {
$pls = new Pools();
$pls->add_post_from_tag($matches[1], $this->id);
}
$ttpe = new TagTermParseEvent($tag, $this->id);
send_event($ttpe);
if($ttpe->is_metatag()) {
continue;
}

View File

@ -36,7 +36,7 @@ _d("WH_SPLITS", 1); // int how many levels of subfolders to put in
_d("VERSION", 'trunk'); // string shimmie version
_d("TIMEZONE", null); // string timezone
_d("MIN_FREE_SPACE",100*1024*1024); // int disable uploading if there's less than MIN_FREE_SPACE bytes free space
_d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,setup,upgrade,handle_404,comment,tag_list,index,tag_edit,alias_editor,hellban"); // extensions to always enable
_d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,setup,upgrade,handle_404,comment,tag_list,index,tag_edit,alias_editor"); // extensions to always enable
_d("EXTRA_EXTS", ""); // optional extra extensions

View File

@ -164,7 +164,7 @@ class AdminPage extends Extension {
global $page;
$matches = array();
preg_match("#^(?P<proto>\w+)\:(?:user=(?P<user>\w+)(?:;|$)|password=(?P<password>\w+)(?:;|$)|host=(?P<host>[\w\.\-]+)(?:;|$)|dbname=(?P<dbname>[\w_]+)(?:;|$))+#", DATABASE_DSN, $matches);
preg_match("#^(?P<proto>\w+)\:(?:user=(?P<user>\w+)(?:;|$)|password=(?P<password>\w*)(?:;|$)|host=(?P<host>[\w\.\-]+)(?:;|$)|dbname=(?P<dbname>[\w_]+)(?:;|$))+#", DATABASE_DSN, $matches);
$software = $matches['proto'];
$username = $matches['user'];
$password = $matches['password'];
@ -184,6 +184,8 @@ class AdminPage extends Extension {
break;
}
//FIXME: .SQL dump is empty if cmd doesn't exist
$page->set_mode("data");
$page->set_type("application/x-unknown");
$page->set_filename('shimmie-'.date('Ymd').'.sql');
@ -195,67 +197,59 @@ class AdminPage extends Extension {
private function download_all_images() {
global $database, $page;
$zip = new ZipArchive;
$images = $database->get_all("SELECT * FROM images");
$images = $database->get_all("SELECT hash, ext FROM images");
$filename = data_path('imgdump-'.date('Ymd').'.zip');
if($zip->open($filename, 1 ? ZIPARCHIVE::OVERWRITE:ZIPARCHIVE::CREATE) === TRUE){
$zip = new ZipArchive;
if($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE) === TRUE){
foreach($images as $img){
$hash = $img["hash"];
preg_match("^[A-Za-z0-9]{2}^", $hash, $matches);
$img_loc = "images/".$matches[0]."/".$hash;
if(file_exists($img_loc)){
$zip->addFile($img_loc, $hash.".".$img["ext"]);
}
$img_loc = warehouse_path("images", $img["hash"], FALSE);
$zip->addFile($img_loc, $img["hash"].".".$img["ext"]);
}
$zip->close();
}
$page->set_mode("redirect");
$page->set_redirect(make_link($filename)); //Fairly sure there is better way to do this..
//TODO: Delete file after downloaded?
$page->set_redirect(make_link($filename)); //TODO: Delete file after downloaded?
return false; // we do want a redirect, but a manual one
}
private function reset_image_ids() {
global $database;
//This might be a bit laggy on boards with lots of images (?)
//Seems to work fine with 1.2k~ images though.
$i = 0;
$image = $database->get_all("SELECT * FROM images ORDER BY images.id ASC");
/*$score_log = $database->get_all("SELECT message FROM score_log");*/
foreach($image as $img){
$xid = $img[0];
$i = $i + 1;
$table = array( //Might be missing some tables?
"image_tags", "tag_histories", "image_reports", "comments", "user_favorites", "tag_histories",
"numeric_score_votes", "pool_images", "slext_progress_cache", "notes");
$sql =
"SET FOREIGN_KEY_CHECKS=0;
UPDATE images
SET id=".$i.
" WHERE id=".$xid.";"; //id for images
foreach($table as $tbl){
$sql .= "
UPDATE ".$tbl."
SET image_id=".$i."
WHERE image_id=".$xid.";";
}
/*foreach($score_log as $sl){
//This seems like a bad idea.
//TODO: Might be better for log_info to have an $id option (which would then affix the id to the table?)
preg_replace(".Image \\#[0-9]+.", "Image #".$i, $sl);
}*/
$sql .= " SET FOREIGN_KEY_CHECKS=1;";
$database->execute($sql);
}
$count = (count($image)) + 1;
$database->execute("ALTER TABLE images AUTO_INCREMENT=".$count);
//TODO: Make work with PostgreSQL + SQLite
//TODO: Update score_log (Having an optional ID column for score_log would be nice..)
preg_match("#^(?P<proto>\w+)\:(?:user=(?P<user>\w+)(?:;|$)|password=(?P<password>\w*)(?:;|$)|host=(?P<host>[\w\.\-]+)(?:;|$)|dbname=(?P<dbname>[\w_]+)(?:;|$))+#", DATABASE_DSN, $matches);
if($matches['proto'] == "mysql"){
$tables = $database->get_col("SELECT TABLE_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = :db
AND REFERENCED_COLUMN_NAME = 'id'
AND REFERENCED_TABLE_NAME = 'images'", array("db" => $matches['dbname']));
$i = 1;
$ids = $database->get_col("SELECT id FROM images ORDER BY images.id ASC");
foreach($ids as $id){
$sql = "SET FOREIGN_KEY_CHECKS=0;
UPDATE images SET id={$i} WHERE image_id={$id};";
foreach($tables as $table){
$sql .= "UPDATE {$table} SET image_id={$i} WHERE image_id={$id};";
}
$sql .= " SET FOREIGN_KEY_CHECKS=1;";
$database->execute($sql);
$i++;
}
$database->execute("ALTER TABLE images AUTO_INCREMENT=".(count($ids) + 1));
}elseif($matches['proto'] == "pgsql"){
//TODO: Make this work with PostgreSQL
}elseif($matches['proto'] == "sqlite"){
//TODO: Make this work with SQLite
}
return true;
}
}

View File

@ -38,8 +38,8 @@ class AdminPageTheme extends Themelet {
$html = "";
$html .= $this->button("All tags to lowercase", "lowercase_all_tags", true);
$html .= $this->button("Recount tag use", "recount_tag_user", false);
$html .= $this->button("Download all images", "image_dump", false);
$html .= $this->button("Recount tag use", "recount_tag_use", false);
$html .= $this->button("Download all images", "download_all_images", false);
$html .= $this->button("Download database contents", "database_dump", false);
if($database->get_driver_name() == "mysql")
$html .= $this->button("Reset image IDs", "reset_image_ids", true);

View File

@ -8,82 +8,75 @@
* Documentation:
* Simply enable this extention in the extention manager to enable arrow key navigation.
*/
class ArrowkeyNavigation extends Extension {
# Adds functionality for post/view on images
public function onDisplayingImage(DisplayingImageEvent $event) {
$prev_url = make_http(make_link("post/prev/".$event->image->id));
$next_url = make_http(make_link("post/next/".$event->image->id));
$this->add_arrowkeys_code($prev_url, $next_url);
}
# Adds functionality for post/list
public function onPageRequest(PageRequestEvent $event) {
if($event->page_matches("post/list")) {
$pageinfo = $this->get_list_pageinfo($event);
$prev_url = make_http(make_link("post/list/".$pageinfo["prev"]));
$next_url = make_http(make_link("post/list/".$pageinfo["next"]));
$this->add_arrowkeys_code($prev_url, $next_url);
}
}
# adds the javascript to the page with the given urls
private function add_arrowkeys_code($prev_url, $next_url) {
global $page;
class ArrowkeyNavigation extends Extension {
# Adds functionality for post/view on images
public function onDisplayingImage(DisplayingImageEvent $event) {
$prev_url = make_http(make_link("post/prev/".$event->image->id));
$next_url = make_http(make_link("post/next/".$event->image->id));
$this->add_arrowkeys_code($prev_url, $next_url);
}
$page->add_html_header("<script type=\"text/javascript\">
document.onkeyup=checkKeycode;
function checkKeycode(e)
{
var keycode;
if(window.event) keycode=window.event.keyCode;
else if(e) keycode=e.which;
# Adds functionality for post/list
public function onPageRequest(PageRequestEvent $event) {
if($event->page_matches("post/list")) {
$pageinfo = $this->get_list_pageinfo($event);
$prev_url = make_http(make_link("post/list/".$pageinfo["prev"]));
$next_url = make_http(make_link("post/list/".$pageinfo["next"]));
$this->add_arrowkeys_code($prev_url, $next_url);
}
}
if (e.srcElement.tagName != \"INPUT\")
{
if(keycode==\"37\") window.location.href='$prev_url';
else if(keycode==\"39\") window.location.href='$next_url';
}
}
</script>");
}
# returns info about the current page number
private function get_list_pageinfo($event) {
global $config, $database;
// get the amount of images per page
$images_per_page = $config->get_int('index_images');
// if there are no tags, use default
if ($event->get_arg(1) == null){
$prefix = "";
$page_number = (int)$event->get_arg(0);
$total_pages = ceil($database->get_one(
"SELECT COUNT(*) FROM images") / $images_per_page);
}
else { // if there are tags, use pages with tags
$prefix = $event->get_arg(0)."/";
$page_number = (int)$event->get_arg(1);
$total_pages = ceil($database->get_one(
"SELECT count FROM tags WHERE tag=:tag",
array("tag"=>$event->get_arg(0))) / $images_per_page);
}
// creates previous & next values
// When previous first page, go to last page
if ($page_number <= 1) $prev = $total_pages;
else $prev = $page_number-1;
if ($page_number >= $total_pages) $next = 1;
else $next = $page_number+1;
// Create return array
$pageinfo = array(
"prev" => $prefix.$prev,
"next" => $prefix.$next,
);
return $pageinfo;
}
# adds the javascript to the page with the given urls
private function add_arrowkeys_code($prev_url, $next_url) {
global $page;
$page->add_html_header("<script type=\"text/javascript\">
(function($){
$(document).keyup(function(e) {
if($(e.target).is('input', 'textarea')){ return; }
if (e.keyCode == 37) { window.location.href = '{$prev_url}'; }
else if (e.keyCode == 39) { window.location.href = '{$next_url}'; }
});
})(jQuery);
</script>", 60);
}
# returns info about the current page number
private function get_list_pageinfo($event) {
global $config, $database;
// get the amount of images per page
$images_per_page = $config->get_int('index_images');
// if there are no tags, use default
if ($event->get_arg(1) == null){
$prefix = "";
$page_number = (int)$event->get_arg(0);
$total_pages = ceil($database->get_one(
"SELECT COUNT(*) FROM images") / $images_per_page);
}
else { // if there are tags, use pages with tags
$prefix = $event->get_arg(0)."/";
$page_number = (int)$event->get_arg(1);
$total_pages = ceil($database->get_one(
"SELECT count FROM tags WHERE tag=:tag",
array("tag"=>$event->get_arg(0))) / $images_per_page);
}
// creates previous & next values
// When previous first page, go to last page
if ($page_number <= 1) $prev = $total_pages;
else $prev = $page_number-1;
if ($page_number >= $total_pages) $next = 1;
else $next = $page_number+1;
// Create return array
$pageinfo = array(
"prev" => $prefix.$prev,
"next" => $prefix.$next,
);
return $pageinfo;
}
}
?>

View File

@ -45,7 +45,7 @@ class Artists extends Extension {
public function onSearchTermParse(SearchTermParseEvent $event) {
$matches = array();
if(preg_match("/^author[=|:](.*)$/", $event->term, $matches)) {
if(preg_match("/^author[=|:](.*)$/i", $event->term, $matches)) {
$char = $matches[1];
$event->add_querylet(new Querylet("Author = :author_char", array("author_char"=>$char)));
}

View File

@ -1,6 +1,6 @@
<?php
/*
* Name: Bulk Remove (Beta)
* Name: [Beta] Bulk Remove
* Author: Drudex Software <support@drudexsoftware.com>
* Link: http://www.drudexsoftware.com/
* License: GPLv2

View File

@ -1,6 +1,6 @@
<?php
/**
* Name: Chatbox (Beta)
* Name: [Beta] Chatbox
* Author: Drudex Software <support@drudexsoftware.com>
* Link: http://www.drudexsoftware.com
* License: GPLv2

View File

@ -262,7 +262,7 @@ class CommentList extends Extension {
public function onSearchTermParse(SearchTermParseEvent $event) {
$matches = array();
if(preg_match("/^comments([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) {
if(preg_match("/^comments([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$comments = $matches[2];
$event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM comments GROUP BY image_id HAVING count(image_id) $cmp $comments)"));

View File

@ -117,7 +117,7 @@ class Favorites extends Extension {
public function onSearchTermParse(SearchTermParseEvent $event) {
$matches = array();
if(preg_match("/^favorites([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) {
if(preg_match("/^favorites([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$favorites = $matches[2];
$event->add_querylet(new Querylet("images.id IN (SELECT id FROM images WHERE favorites $cmp $favorites)"));

View File

@ -1,4 +1,8 @@
<?php
/*
* Name: [Beta] Hellban
*/
class HellBan extends Extension {
public function onPageRequest(PageRequestEvent $event) {
global $page, $user;

View File

@ -109,6 +109,7 @@
* <li>downvoted_by=Username -- search for a user's dislikes
* <li>upvoted_by_id=UserID -- search for a user's likes by user ID
* <li>downvoted_by_id=UserID -- search for a user's dislikes by user ID
* <li>order=score_(ASC, DESC) -- find all images sorted from by score
* </ul>
* <li>Image Rating
* <ul>
@ -141,6 +142,11 @@
* <li>pool=(PoolID, any, none) -- search for images in a pool by PoolID.
* <li>pool_by_name=PoolName -- search for images in a pool by PoolName. underscores are replaced with spaces
* </ul>
* <li>Post Relationships
* <ul>
* <li>parent=(parentID, any, none) -- search for images by parentID / if they have, do not have a parent
* <li>child=(any, none) -- search for images which have, or do not have children
* </ul>
* </ul>
*/
@ -295,12 +301,12 @@ class Index extends Extension {
public function onSearchTermParse(SearchTermParseEvent $event) {
$matches = array();
// check for tags first as tag based searches are more common.
if(preg_match("/^tags([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) {
if(preg_match("/^tags([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$tags = $matches[2];
$event->add_querylet(new Querylet('images.id IN (SELECT DISTINCT image_id FROM image_tags GROUP BY image_id HAVING count(image_id) '.$cmp.' '.$tags.')'));
}
else if(preg_match("/^ratio([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+):(\d+)$/", $event->term, $matches)) {
else if(preg_match("/^ratio([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+):(\d+)$/i", $event->term, $matches)) {
$cmp = preg_replace('/^:/', '=', $matches[1]);
$args = array("width{$this->stpen}"=>int_escape($matches[2]), "height{$this->stpen}"=>int_escape($matches[3]));
$event->add_querylet(new Querylet("width / height $cmp :width{$this->stpen} / :height{$this->stpen}", $args));
@ -326,28 +332,28 @@ class Index extends Extension {
else if(preg_match("/^(source)[=|:](.*)$/i", $event->term, $matches)) {
$source = strtolower($matches[2]);
if(preg_match("/^(any|none)$/", $source)){
if(preg_match("/^(any|none)$/i", $source)){
$not = ($source == "any" ? "NOT" : "");
$event->add_querylet(new Querylet("images.source IS $not NULL"));
}else{
$event->add_querylet(new Querylet('images.source LIKE :src', array("src"=>"%$source%")));
}
}
else if(preg_match("/^posted([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])([0-9-]*)$/", $event->term, $matches)) {
else if(preg_match("/^posted([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])([0-9-]*)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$val = $matches[2];
$event->add_querylet(new Querylet("images.posted $cmp :posted{$this->stpen}", array("posted{$this->stpen}"=>$val)));
}
else if(preg_match("/^size([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)x(\d+)$/", $event->term, $matches)) {
else if(preg_match("/^size([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)x(\d+)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$args = array("width{$this->stpen}"=>int_escape($matches[2]), "height{$this->stpen}"=>int_escape($matches[3]));
$event->add_querylet(new Querylet("width $cmp :width{$this->stpen} AND height $cmp :height{$this->stpen}", $args));
}
else if(preg_match("/^width([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) {
else if(preg_match("/^width([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$event->add_querylet(new Querylet("width $cmp :width{$this->stpen}", array("width{$this->stpen}"=>int_escape($matches[2]))));
}
else if(preg_match("/^height([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) {
else if(preg_match("/^height([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$event->add_querylet(new Querylet("height $cmp :height{$this->stpen}",array("height{$this->stpen}"=>int_escape($matches[2]))));
}

View File

@ -214,7 +214,7 @@ class Notes extends Extension {
$notes = int_escape($matches[1]);
$event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM notes WHERE note = $notes)"));
}
else if(preg_match("/^notes([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)%/", $event->term, $matches)) {
else if(preg_match("/^notes([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)%/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$notes = $matches[2];
$event->add_querylet(new Querylet("images.id IN (SELECT id FROM images WHERE notes $cmp $notes)"));

View File

@ -1,6 +1,6 @@
$(function() {
if(window.notes) {
$('#main_image').imgNotes(window.notes);
$('#main_image').imgNotes({notes: window.notes});
}
$('#cancelnote').click(function(){

View File

@ -63,7 +63,7 @@ class NumericScore extends Extension {
}
die($html);
}
if($event->page_matches("numeric_score_vote") && $user->check_auth_token()) {
else if($event->page_matches("numeric_score_vote") && $user->check_auth_token()) {
if(!$user->is_anonymous()) {
$image_id = int_escape($_POST['image_id']);
$char = $_POST['vote'];
@ -76,7 +76,7 @@ class NumericScore extends Extension {
$page->set_redirect(make_link("post/view/$image_id"));
}
}
if($event->page_matches("numeric_score/remove_votes_on") && $user->check_auth_token()) {
else if($event->page_matches("numeric_score/remove_votes_on") && $user->check_auth_token()) {
if($user->can("edit_other_vote")) {
$image_id = int_escape($_POST['image_id']);
$database->execute(
@ -89,83 +89,62 @@ class NumericScore extends Extension {
$page->set_redirect(make_link("post/view/$image_id"));
}
}
if($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) {
else if($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) {
if($user->can("edit_other_vote")) {
$this->delete_votes_by(int_escape($_POST['user_id']));
$page->set_mode("redirect");
$page->set_redirect(make_link());
}
}
if($event->page_matches("popular_by_day") || $event->page_matches("popular_by_month") || $event->page_matches("popular_by_year")) {
$t_images = $config->get_int("index_images");
else if($event->page_matches("popular_by_day") || $event->page_matches("popular_by_month") || $event->page_matches("popular_by_year")) {
//FIXME: popular_by isn't linked from anywhere
list($day, $month, $year) = array(date("d"), date("m"), date("Y"));
//TODO: Add Popular_by_week.
if(!empty($_GET['day'])){
$D = (int) $_GET['day'];
if($D >= 1 && $D <= 31) $day = $D;
}
if(!empty($_GET['month'])){
$M = (int) $_GET['month'];
if($M >= 1 && $M <= 12) $month = $M;
}
if(!empty($_GET['year'])){
$Y = (int) $_GET['year'];
if($Y >= 1970 && $Y < 2100) $year = $Y;
}
//year
if(empty($_GET['year'])){
$year = date("Y");
}else{
$year = $_GET['year'];
}
//month
if(empty($_GET['month']) || int_escape($_GET['month']) > 12){
$month = date("m");
}else{
$month = $_GET['month'];
}
//day
if(empty($_GET['day']) || int_escape($_GET['day']) > 31){
$day = date("d");
}else{
$day = $_GET['day'];
}
$totaldate = $year."/".$month."/".$day;
$sql =
"SELECT * FROM images
WHERE EXTRACT(YEAR FROM posted) = :year
";
$agrs = array("limit" => $t_images, "year" => $year);
$sql = "SELECT id FROM images
WHERE EXTRACT(YEAR FROM posted) = :year
";
$args = array("limit" => $config->get_int("index_images"), "year" => $year);
if($event->page_matches("popular_by_day")){
$sql .=
"AND EXTRACT(MONTH FROM posted) = :month
AND EXTRACT(DAY FROM posted) = :day
AND NOT numeric_score=0
";
//array_push doesn't seem to like using double arrows
//this requires us to instead create two arrays and merge
$sgra = array("month" => $month, "day" => $day);
$args = array_merge($agrs, $sgra);
AND EXTRACT(DAY FROM posted) = :day";
$args = array_merge($args, array("month" => $month, "day" => $day));
$dte = array($totaldate, date("F jS, Y", (strtotime($totaldate))), "\\y\\e\\a\\r\\=Y\\&\\m\\o\\n\\t\\h\\=m\\&\\d\\a\\y\\=d", "day");
}
if($event->page_matches("popular_by_month")){
$sql .=
"AND EXTRACT(MONTH FROM posted) = :month
AND NOT numeric_score=0
";
$sgra = array("month" => $month);
$args = array_merge($agrs, $sgra);
else if($event->page_matches("popular_by_month")){
$sql .= "AND EXTRACT(MONTH FROM posted) = :month";
$title = date("F Y", (strtotime($totaldate)));
$dte = array($totaldate, $title, "\\y\\e\\a\\r\\=Y\\&\\m\\o\\n\\t\\h\\=m", "month");
$args = array_merge($args, array("month" => $month));
$dte = array($totaldate, date("F Y", (strtotime($totaldate))), "\\y\\e\\a\\r\\=Y\\&\\m\\o\\n\\t\\h\\=m", "month");
}
if($event->page_matches("popular_by_year")){
$sql .= "AND NOT numeric_score=0";
$dte = array($totaldate, $year, "\y\e\a\\r\=Y", "year");
$args = $agrs;
else if($event->page_matches("popular_by_year")){
$dte = array($totaldate, $year, "\\y\\e\\a\\r\=Y", "year");
}
$sql .= " ORDER BY numeric_score DESC LIMIT :limit OFFSET 0";
$sql .= " AND NOT numeric_score=0 ORDER BY numeric_score DESC LIMIT :limit OFFSET 0";
//filter images by year/score != 0 > limit to max images on one page > order from highest to lowest score
$result = $database->get_all($sql, $args);
//filter images by score != 0 + date > limit to max images on one page > order from highest to lowest score
$result = $database->get_col($sql, $args);
$images = array();
foreach($result as $singleResult) {
$images[] = Image::by_id($singleResult["id"]);
}
foreach($result as $id) { $images[] = Image::by_id($id); }
$this->theme->view_popular($images, $dte);
}
}
@ -217,12 +196,12 @@ class NumericScore extends Extension {
public function onSearchTermParse(SearchTermParseEvent $event) {
$matches = array();
if(preg_match("/^score([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(-?\d+)$/", $event->term, $matches)) {
if(preg_match("/^score([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(-?\d+)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$score = $matches[2];
$event->add_querylet(new Querylet("numeric_score $cmp $score"));
}
if(preg_match("/^upvoted_by[=|:](.*)$/", $event->term, $matches)) {
else if(preg_match("/^upvoted_by[=|:](.*)$/i", $event->term, $matches)) {
$duser = User::by_name($matches[1]);
if(is_null($duser)) {
throw new SearchTermParseException(
@ -232,7 +211,7 @@ class NumericScore extends Extension {
"images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=1)",
array("ns_user_id"=>$duser->id)));
}
if(preg_match("/^downvoted_by[=|:](.*)$/", $event->term, $matches)) {
else if(preg_match("/^downvoted_by[=|:](.*)$/i", $event->term, $matches)) {
$duser = User::by_name($matches[1]);
if(is_null($duser)) {
throw new SearchTermParseException(
@ -242,18 +221,39 @@ class NumericScore extends Extension {
"images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=-1)",
array("ns_user_id"=>$duser->id)));
}
if(preg_match("/^upvoted_by_id[=|:](\d+)$/", $event->term, $matches)) {
else if(preg_match("/^upvoted_by_id[=|:](\d+)$/i", $event->term, $matches)) {
$iid = int_escape($matches[1]);
$event->add_querylet(new Querylet(
"images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=1)",
array("ns_user_id"=>$iid)));
}
if(preg_match("/^downvoted_by_id[=|:](\d+)$/", $event->term, $matches)) {
else if(preg_match("/^downvoted_by_id[=|:](\d+)$/i", $event->term, $matches)) {
$iid = int_escape($matches[1]);
$event->add_querylet(new Querylet(
"images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=-1)",
array("ns_user_id"=>$iid)));
}
else if(preg_match("/^order[=|:](numeric_)?(score)[_]?(desc|asc)?$/i", $event->term, $matches)){
global $order_sql;
$default_order_for_column = "DESC";
$sort = isset($matches[3]) ? strtoupper($matches[3]) : $default_order_for_column;
$order_sql = "numeric_score $sort";
$event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag
}
}
public function onTagTermParse(TagTermParseEvent $event) {
$matches = array();
if(preg_match("/^vote[=|:](up|down|remove)$/", $event->term, $matches)) {
global $user;
$score = ($matches[1] == "up" ? 1 : ($matches[1] == "down" ? -1 : 0));
if(!$user->is_anonymous()) {
send_event(new NumericScoreSetEvent($event->id, $user, $score));
}
}
if(!empty($matches)) $event->metatag = true;
}
private function install() {

View File

@ -62,27 +62,28 @@ class NumericScoreTheme extends Themelet {
}
public function view_popular($images, $dte) {
global $user, $page;
global $page, $config;
$pop_images = '';
$pop_images = "";
foreach($images as $image) {
$thumb_html = $this->build_thumb_html($image);
$pop_images .= '<span class="thumb">'.
'<a href="$image_link">'.$thumb_html.'</a>'.
'</span>';
$pop_images .= $this->build_thumb_html($image)."\n";
}
$b_dte = make_link("popular_by_".$dte[3]."?".date($dte[2], (strtotime('-1 '.$dte[3], strtotime($dte[0])))));
$f_dte = make_link("popular_by_".$dte[3]."?".date($dte[2], (strtotime('+1 '.$dte[3], strtotime($dte[0])))));
$html = '<center><h3><a href="'.$b_dte.'">&laquo;</a> '.$dte[1]
.' <a href="'.$f_dte.'">&raquo;</a>'
.'</h3></center>
<br>'.$pop_images;
$html = "\n".
"<center>\n".
" <h3>\n".
" <a href='{$b_dte}'>&laquo;</a> {$dte[1]} <a href='{$f_dte}'>&raquo;</a>\n".
" </h3>\n".
"</center>\n".
"<br/>\n".$pop_images;
$nav_html = "<a href=".make_link().">Index</a>";
$page->set_heading($config->get_string('title'));
$page->add_block(new Block("Navigation", $nav_html, "left", 10));
$page->add_block(new Block(null, $html, "main", 30));
}

View File

@ -1,6 +1,6 @@
<?php
/*
* Name: [beta] PM triggers
* Name: [Beta] PM triggers
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Send PMs in response to certain events (eg image deletion)
@ -11,7 +11,7 @@ class PMTrigger extends Extension {
$this->send(
$event->image->owner_id,
"[System] An image you uploaded has been deleted",
"Image le gone~ (#{$image->id}, {$image->get_tag_list()})"
"Image le gone~ (#{$event->image->id}, {$event->image->get_tag_list()})"
);
}

View File

@ -293,7 +293,7 @@ class Pools extends Extension {
public function onSearchTermParse(SearchTermParseEvent $event) {
$matches = array();
if(preg_match("/^pool[=|:]([0-9]+|any|none)$/", $event->term, $matches)) {
if(preg_match("/^pool[=|:]([0-9]+|any|none)$/i", $event->term, $matches)) {
$poolID = $matches[1];
if(preg_match("/^(any|none)$/", $poolID)){
@ -303,7 +303,7 @@ class Pools extends Extension {
$event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM pool_images WHERE pool_id = $poolID)"));
}
}
else if(preg_match("/^pool_by_name[=|:](.*)$/", $event->term, $matches)) {
else if(preg_match("/^pool_by_name[=|:](.*)$/i", $event->term, $matches)) {
$poolTitle = str_replace("_", " ", $matches[1]);
$pool = $this->get_single_pool_from_title($poolTitle);
@ -313,21 +313,26 @@ class Pools extends Extension {
}
}
public function add_post_from_tag(/*str*/ $poolTag, /*int*/ $imageID){
$poolTag = str_replace("_", " ", $poolTag);
//First check if pool tag is a title
if(ctype_digit($poolTag)){
//If string only contains numeric characters, assume it is $poolID
if($this->get_single_pool($poolTag)){ //Make sure pool exists
$this->add_post($poolTag, $imageID);
public function onTagTermParse(TagTermParseEvent $event) {
$matches = array();
if(preg_match("/^pool[=|:](.*)$/i", $event->term, $matches)) {
global $user;
$poolTag = (string) str_replace("_", " ", $matches[1]);
$pool = null;
if(ctype_digit($poolTag)){ //If only digits, assume PoolID
$pool = $this->get_single_pool($poolTag);
}else{ //assume PoolTitle
$pool = $this->get_single_pool_from_title($poolTag);
}
}else{
//If string doesn't contain only numeric characters, check to see if tag is title.
$pool = $this->get_single_pool_from_title($poolTag);
if($pool){
$this->add_post($pool['id'], $imageID);
if($pool ? $this->have_permission($user, $pool) : FALSE){
$this->add_post($pool['id'], $event->id, true);
}
}
if(!empty($matches)) $event->metatag = true;
}
/* ------------------------------------------------- */
@ -830,9 +835,9 @@ class Pools extends Extension {
/*
* HERE WE ADD A SIMPLE POST FROM POOL
* USED WITH FOREACH IN revert_history()
* USED WITH FOREACH IN revert_history() & onTagTermParse()
*/
private function add_post(/*int*/ $poolID, /*int*/ $imageID) {
private function add_post(/*int*/ $poolID, /*int*/ $imageID, $history=false) {
global $database;
if(!$this->check_post($poolID, $imageID)) {
@ -843,19 +848,29 @@ class Pools extends Extension {
}
$database->execute("UPDATE pools SET posts=(SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid) WHERE id=:pid", array("pid"=>$poolID));
if($history){
$count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID));
$this->add_history($poolID, 1, $imageID, $count);
}
}
/*
* HERE WE REMOVE A SIMPLE POST FROM POOL
* USED WITH FOREACH IN revert_history()
* USED WITH FOREACH IN revert_history() & onTagTermParse()
*/
private function delete_post(/*int*/ $poolID, /*int*/ $imageID) {
private function delete_post(/*int*/ $poolID, /*int*/ $imageID, $history=false) {
global $database;
$database->execute("DELETE FROM pool_images WHERE pool_id = :pid AND image_id = :iid", array("pid"=>$poolID, "iid"=>$imageID));
$database->execute("UPDATE pools SET posts=(SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid) WHERE id=:pid", array("pid"=>$poolID));
if($history){
$count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID));
$this->add_history($poolID, 0, $imageID, $count);
}
}
}

View File

@ -121,7 +121,9 @@ class PoolsTheme extends Themelet {
$this->sidebar_options($page, $pool, $check_all);
}
}
$page->add_block(new Block(html_escape($pool['title']), html_escape($pool['description']), "main", 10));
$bb = new BBCode();
$page->add_block(new Block(html_escape($pool['title']), $bb->format($pool['description']), "main", 10));
}
else {
$pool_info = '
@ -412,8 +414,15 @@ class PoolsTheme extends Themelet {
$html .= "</tbody></table>";
$nav_html = '
<a href="'.make_link().'">Index</a>
<br><a href="'.make_link("pool/new").'">Create Pool</a>
<br><a href="'.make_link("pool/updated").'">Pool Changes</a>
';
$page->set_title("Recent Changes");
$page->set_heading("Recent Changes");
$page->add_block(new Block("Navigation", $nav_html, "left", 10));
$page->add_block(new Block("Recent Changes", $html, "main", 10));
$this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages);

View File

@ -45,11 +45,18 @@ class RandomImage extends Extension {
$page->set_data(file_get_contents($image->get_image_filename()));
}
}
if($action === "view") {
else if($action === "view") {
if(!is_null($image)) {
send_event(new DisplayingImageEvent($image, $page));
}
}
else if($action === "widget") {
if(!is_null($image)) {
$page->set_mode("data");
$page->set_type("text/html");
$page->set_data($this->theme->build_thumb_html($image));
}
}
}
}

View File

@ -13,56 +13,42 @@
class RandomList extends Extension {
public function onPageRequest(PageRequestEvent $event) {
global $config, $page;
if($event->page_matches("random")) {
// set vars
$page->title = "Random Images";
$images_per_page = $config->get_int("random_images_list_count", 12);
$random_images = array();
$random_html = "<b>Refresh the page to view more images</b>
<div class='shm-image-list'>";
// generate random images
for ($i = 0; $i < $images_per_page; $i++)
array_push($random_images, Image::by_random());
if($event->page_matches("random")) {
// set vars
$page->title = "Random Images";
$images_per_page = $config->get_int("random_images_list_count", 12);
$random_images = array();
$random_html = "<b>Refresh the page to view more images</b>
<div class='shm-image-list'>";
// create html to display images
foreach ($random_images as $image)
$random_html .= $this->build_random_html($image);
// display it
$random_html .= "</div>";
$page->add_block(new Block("Random Images", $random_html));
// generate random images
for ($i = 0; $i < $images_per_page; $i++)
array_push($random_images, Image::by_random());
// create html to display images
foreach ($random_images as $image)
$random_html .= $this->theme->build_thumb_html($image);
// display it
$random_html .= "</div>";
$page->add_block(new Block("Random Images", $random_html));
}
}
public function onInitExt(InitExtEvent $event) {
global $config;
$config->set_default_int("random_images_list_count", 12);
}
public function onSetupBuilding(SetupBuildingEvent $event) {
$sb = new SetupBlock("Random Images List");
// custom headers
$sb->add_int_option("random_images_list_count",
"Amount of Random images to display ");
$event->panel->add_block($sb);
}
private function build_random_html(Image $image, $query=null) {
$i_id = int_escape($image->id);
$h_view_link = make_link("post/view/$i_id", $query);
$h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip());
$tsize = get_thumbnail_size($image->width, $image->height);
return "
<a href='$h_view_link' class='thumb shm-thumb' data-post-id='$i_id'>
<img id='thumb_$i_id' height='{$tsize[1]}' width='{$tsize[0]}' class='lazy' data-original='$h_thumb_link' src='/lib/static/grey.gif'><noscript>
<img id='thumb_$i_id' height='{$tsize[1]} width='{$tsize[0]} src='$h_thumb_link'></noscript></a>
";
public function onInitExt(InitExtEvent $event) {
global $config;
$config->set_default_int("random_images_list_count", 12);
}
public function onSetupBuilding(SetupBuildingEvent $event) {
$sb = new SetupBlock("Random Images List");
// custom headers
$sb->add_int_option("random_images_list_count",
"Amount of Random images to display ");
$event->panel->add_block($sb);
}
}
?>

View File

@ -0,0 +1,4 @@
<?php
/* needed for access to build_thumb_html */
class RandomListTheme extends Themelet {}
?>

View File

@ -0,0 +1,123 @@
<?php
/**
* Name: Post Relationships
* Author: Angus Johnston <admin@codeanimu.net>
* License: GPLv2
* Description: Allow posts to have relationships (parent/child).
*/
class Relationships extends Extension {
public function onInitExt(InitExtEvent $event) {
global $config, $database;
// Create the database tables
if ($config->get_int("ext_relationships_version") < 1){
$database->Execute("ALTER TABLE images ADD parent_id INT NULL, ADD INDEX (parent_id);");
$database->Execute("ALTER TABLE images ADD has_children BOOL DEFAULT FALSE NOT NULL;");
$config->set_int("ext_relationships_version", 1);
log_info("relationships", "extension installed");
}
}
public function onImageInfoSet(ImageInfoSetEvent $event) {
global $user;
if(isset($_POST['tag_edit__tags']) ? !preg_match('/parent[=|:]/', $_POST["tag_edit__tags"]) : TRUE) { //Ignore tag_edit__parent if tags contain parent metatag
if (isset($_POST["tag_edit__parent"]) ? ctype_digit($_POST["tag_edit__parent"]) : FALSE) {
$this->set_parent($event->image->id, (int) $_POST["tag_edit__parent"]);
}else{
$this->remove_parent($event->image->id);
}
}
}
public function onDisplayingImage(DisplayingImageEvent $event) {
$this->theme->relationship_info($event->image);
}
public function onSearchTermParse(SearchTermParseEvent $event) {
$matches = array();
if(preg_match("/^parent[=|:]([0-9]+|any|none)$/", $event->term, $matches)) {
$parentID = $matches[1];
if(preg_match("/^(any|none)$/", $parentID)){
$not = ($parentID == "any" ? "NOT" : "");
$event->add_querylet(new Querylet("images.parent_id IS $not NULL"));
}else{
$event->add_querylet(new Querylet("images.parent_id = :pid", array("pid"=>$parentID)));
}
}
else if(preg_match("/^child[=|:](any|none)$/", $event->term, $matches)) {
$not = ($matches[1] == "any" ? "=" : "!=");
$event->add_querylet(new Querylet("images.has_children $not TRUE"));
}
}
public function onTagTermParse(TagTermParseEvent $event) {
$matches = array();
if(preg_match("/^parent[=|:]([0-9]+|none)$/", $event->term, $matches)) {
$parentID = $matches[1];
if($parentID == "none" || $parentID == "0"){
$this->remove_parent($event->id);
}else{
$this->set_parent($event->id, $parentID);
}
}
else if(preg_match("/^child[=|:]([0-9]+)$/", $event->term, $matches)) {
$childID = $matches[1];
$this->set_child($event->id, $childID);
}
if(!empty($matches)) $event->metatag = true;
}
public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event) {
$event->add_part($this->theme->get_parent_editor_html($event->image), 45);
}
public function onImageDeletion(ImageDeletionEvent $event) {
global $database;
if($event->image->has_children){
$database->execute("UPDATE images SET parent_id = NULL WHERE parent_id = :iid", array("iid"=>$event->image->id));
}
if($event->image->parent_id !== NULL){
$database->execute("UPDATE images SET has_children = (SELECT * FROM (SELECT CASE WHEN (COUNT(*) - 1) > 0 THEN 1 ELSE 0 END FROM images WHERE parent_id = :pid) AS sub)
WHERE id = :pid", array("pid"=>$event->image->parent_id));
}
}
private function set_parent(/*int*/ $imageID, /*int*/ $parentID){
global $database;
if($database->get_row("SELECT 1 FROM images WHERE id = :pid", array("pid"=>$parentID))){
$database->execute("UPDATE images SET parent_id = :pid WHERE id = :iid", array("pid"=>$parentID, "iid"=>$imageID));
$database->execute("UPDATE images SET has_children = TRUE WHERE id = :pid", array("pid"=>$parentID));
}
}
private function set_child(/*int*/ $parentID, /*int*/ $childID){
global $database;
if($database->get_row("SELECT 1 FROM images WHERE id = :cid", array("cid"=>$childID))){
$database->execute("UPDATE images SET parent_id = :pid WHERE id = :cid", array("cid"=>$childID, "pid"=>$parentID));
$database->execute("UPDATE images SET has_children = TRUE WHERE id = :pid", array("pid"=>$parentID));
}
}
private function remove_parent(/*int*/ $imageID){
global $database;
$parentID = $database->get_one("SELECT parent_id FROM images WHERE id = :iid", array("iid"=>$imageID));
if($parentID){
$database->execute("UPDATE images SET parent_id = NULL WHERE id = :iid", array("iid"=>$imageID));
$database->execute("UPDATE images SET has_children = (SELECT * FROM (SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM images WHERE parent_id = :pid) AS sub)
WHERE id = :pid", array("pid"=>$parentID));
}
}
}
?>

View File

@ -0,0 +1,15 @@
.thumb IMG {
border-width: 2px !important;
}
.shm-thumb-has_child img {
border-color: lime !important;
}
.shm-thumb-has_parent img {
border-color: #cc0 !important;
}
.shm-thumb-has_child.shm-thumb-has_parent img {
border-color: lime #cc0 #cc0 lime !important;
}

View File

@ -0,0 +1,45 @@
<?php
class RelationshipsTheme extends Themelet {
public function relationship_info($image) {
global $page, $database;
if($image->parent_id !== NULL){
$a = "<a href='".make_link("post/view/".$image->parent_id)."'>parent post</a>";
$page->add_block(new Block(null, "This post belongs to a $a.", "main", 5));
}
if($image->has_children == TRUE){
$ids = $database->get_col("SELECT id FROM images WHERE parent_id = :iid", array("iid"=>$image->id));
$html = "This post has <a href='".make_link('post/list/parent='.$image->id.'/1')."'>".(count($ids) > 1 ? "child posts" : "a child post")."</a>";
$html .= " (post ";
foreach($ids as $id){
$html .= "#<a href='".make_link('post/view/'.$id)."'>{$id}</a>, ";
}
$html = rtrim($html, ", ").").";
$page->add_block(new Block(null, $html, "main", 6));
}
}
public function get_parent_editor_html(Image $image) {
global $user;
$h_parent_id = $image->parent_id;
$s_parent_id = $h_parent_id ?: "None.";
$html = "<tr>\n".
" <th>Parent</th>\n".
" <td>\n".
(!$user->is_anonymous() ?
" <span class='view' style='overflow: hidden; white-space: nowrap;'>{$s_parent_id}</span>\n".
" <input class='edit' type='text' name='tag_edit__parent' type='number' value='{$h_parent_id}'>\n"
:
$s_parent_id
).
" <td>\n".
"</tr>\n";
return $html;
}
}
?>

View File

@ -3,6 +3,34 @@
* Name: Tag Editor
* Author: Shish
* Description: Allow images to have tags assigned to them
* Documentation:
* Here is a list of the tagging metatags available out of the box;
* Shimmie extensions may provide other metatags:
* <ul>
* <li>source=(*, none) eg -- using this metatag will ignore anything set in the "Source" box
* <ul>
* <li>source=http://example.com -- set source to http://example.com
* <li>source=none -- set source to NULL
* </ul>
* </ul>
* <p>Metatags can be followed by ":" rather than "=" if you prefer.
* <br />I.E: "source:http://example.com", "source=http://example.com" etc.
* <p>Some tagging metatags provided by extensions:
* <ul>
* <li>Numeric Score
* <ul>
* <li>vote=(up, down, remove) -- vote, or remove your vote on an image
* </ul>
* <li>Pools
* <ul>
* <li>pool=(PoolID, PoolTitle) -- add post to pool (if exists)
* </ul>
* <li>Post Relationships
* <ul>
* <li>parent=(parentID, none) -- set parent ID of current image
* <li>child=(childID) -- set parent ID of child image to current image ID
* </ul>
* </ul>
*/
/*
@ -72,6 +100,25 @@ class LockSetEvent extends Event {
}
}
/*
* TagTermParseEvent:
* Signal that a tag term needs parsing
*/
class TagTermParseEvent extends Event {
var $term = null;
var $id = null;
var $metatag = false;
public function TagTermParseEvent($term, $id) {
$this->term = $term;
$this->id = $id;
}
public function is_metatag() {
return $this->metatag;
}
}
class TagEdit extends Extension {
public function onPageRequest(PageRequestEvent $event) {
global $user, $page;
@ -112,7 +159,9 @@ class TagEdit extends Extension {
send_event(new TagSetEvent($event->image, $_POST['tag_edit__tags']));
}
if($this->can_source($event->image) && isset($_POST['tag_edit__source'])) {
send_event(new SourceSetEvent($event->image, $_POST['tag_edit__source']));
if(isset($_POST['tag_edit__tags']) ? !preg_match('/source[=|:]/', $_POST["tag_edit__tags"]) : TRUE){
send_event(new SourceSetEvent($event->image, $_POST['tag_edit__source']));
}
}
if($user->can("edit_image_lock")) {
$locked = isset($_POST['tag_edit__locked']) && $_POST['tag_edit__locked']=="on";
@ -169,6 +218,16 @@ class TagEdit extends Extension {
$event->add_part($this->theme->get_lock_editor_html($event->image), 42);
}
public function onTagTermParse(TagTermParseEvent $event) {
$matches = array();
if(preg_match("/^source[=|:](.*)$/i", $event->term, $matches)) {
$source = ($matches[1] !== "none" ? $matches[1] : null);
send_event(new SourceSetEvent(Image::by_id($event->id), $source));
}
if(!empty($matches)) $event->metatag = true;
}
private function can_tag(Image $image) {
global $config, $user;
@ -189,6 +248,18 @@ class TagEdit extends Extension {
log_info("tag_edit", "Mass editing tags: '$search' -> '$replace'");
if(count($search_set) == 1 && count($replace_set) == 1) {
$images = Image::find_images(0, 10, $replace_set);
if(count($images) == 0) {
log_info("tag_edit", "No images found with target tag, doing in-place rename");
$database->execute("DELETE FROM tags WHERE tag=:replace",
array("replace" => $replace_set[0]));
$database->execute("UPDATE tags SET tag=:replace WHERE tag=:search",
array("replace" => $replace_set[0], "search" => $search_set[0]));
return;
}
}
$last_id = -1;
while(true) {
// make sure we don't look at the same images twice.

View File

@ -1,166 +1,111 @@
<?php
/**
* Name: Update
* Name: [Beta] Update
* Author: DakuTree <dakutree@codeanimu.net>
* Link: http://www.codeanimu.net
* License: GPLv2
* Description: Shimmie updater! (Requires php-curl library and admin panel extension)
* Description: Shimmie updater! (Requires admin panel extension & transload engine (cURL/fopen/Wget))
*/
class Update extends Extension {
public function onInitExt(InitExtEvent $event) {
global $config;
$config->set_default_string("update_guser", "shish");
$config->set_default_string("update_grepo", "shimmie2");
$config->set_default_string("update_guserrepo", "shish/shimmie2");
$config->set_default_string("commit_hash", "unknown");
$config->set_default_string("commit_time", "unknown");
$config->set_default_string("update_time", "01/01/1970");
}
public function onSetupBuilding(SetupBuildingEvent $event) {
$sb = new SetupBlock("Update");
$sb->add_text_option("update_guser", "User: ");
$sb->add_text_option("update_grepo", "<br>Repo: ");
$sb->add_text_option("update_guserrepo", "User/Repo: ");
$event->panel->add_block($sb);
}
public function onAdminBuilding(AdminBuildingEvent $event) {
global $config, $page;
$latestCommit = $this->get_latest_commit();
if(is_null($latestCommit)) return;
$commitMessage = $latestCommit["commit"]["message"];
$commitDT = explode("T", $latestCommit["commit"]["committer"]["date"]);
$commitTD = explode("-", $commitDT[1]);
$commitDateTime = $commitDT[0]." (".$commitTD[0].")";
$commitSHA = substr($latestCommit["sha"],0,7);
$html = "".
"Current Commit: ".$config->get_string('commit_hash')." | ".$config->get_string('commit_time').
"<br>Latest Commit: ".$commitSHA." | ".$commitDateTime." | ".$commitMessage.
"<br><a href='" . make_link('update') . "'>Update</a>".
"";
$page->add_block(new Block("Software Update", $html, "main"));
global $config;
if($config->get_string('transload_engine') !== "none"){
$this->theme->display_admin_block();
}
}
public function onPageRequest(PageRequestEvent $event) {
global $config, $user;
if($event->page_matches("update") && $user->is_admin()) {
$ok = $this->update_shimmie();
global $config, $user, $page;
if($user->is_admin() && isset($_GET['sha'])){
if($event->page_matches("update/download")){
$ok = $this->download_shimmie();
$page->set_mode("redirect");
if($ok) $page->set_redirect(make_link("update/update", "sha=".$_GET['sha']));
else $page->set_redirect(make_link("admin")); //TODO: Show error?
}elseif($event->page_matches("update/update")){
$ok = $this->update_shimmie();
$page->set_mode("redirect");
if($ok) $page->set_redirect(make_link("admin")); //TODO: Show success?
else $page->set_redirect(make_link("admin")); //TODO: Show error?
}
}
}
private function get_latest_commit() {
private function download_shimmie() {
global $config;
if(!function_exists("curl_init")) return null;
$commitSHA = $_GET['sha'];
$g_userrepo = $config->get_string('update_guserrepo');
//Grab latest info via JSON.
$g_user = $config->get_string("update_guser");
$g_repo = $config->get_string("update_grepo");
$base = "https://api.github.com/repos/".$g_user."/".$g_repo."/commits";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $base);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$content = curl_exec($curl);
curl_close($curl);
$commits = json_decode($content, true);
return $commits[0];
$url = "https://codeload.github.com/".$g_userrepo."/zip/".$commitSHA;
$filename = "./data/update_{$commitSHA}.zip";
log_info("update", "Attempting to download Shimmie commit: ".$commitSHA);
if($headers = transload($url, $filename)){
if(($headers['Content-Type'] !== "application/zip") || ((int) $headers['Content-Length'] !== filesize($filename))){
unlink("./data/update_{$commitSHA}.zip");
log_warning("update", "Download failed: not zip / not same size as remote file.");
return false;
}
return true;
}
log_warning("update", "Download failed to download.");
return false;
}
private function update_shimmie() {
//This is a REALLY ugly function. (Damn my limited PHP knowledge >_<)
global $config, $page;
$latestCommit = $this->get_latest_commit();
if(is_null($latestCommit)) return;
$commitSHA = $_GET['sha'];
$g_userrepo = $config->get_string('update_guserrepo');
$commitDT = explode("T", $latestCommit["commit"]["committer"]["date"]);
$commitTD = explode("-", $commitDT[1]);
$commitDateTime = $commitDT[0]." (".$commitTD[0].")";
$commitSHA = substr($latestCommit["sha"],0,7);
log_info("update", "Download succeeded. Attempting to update Shimmie.");
$config->set_bool("in_upgrade", TRUE);
$ok = FALSE;
$html = "";
$url = "http://nodeload.github.com/".$g_user."/".$g_repo."/zipball/".$commitSHA;
$mfile = "master.zip";
if(glob("*-shimmie2-".$commitSHA)) { //#3
$dir = glob("*-shimmie2-".$commitSHA);
preg_match('@^([a-zA-Z0-9]+\-[0-9a-z]+\-)([^/]+)@i', $dir[0], $matches);
if(!empty($matches[2])) {
$html .= "commit: ".$matches[2];
$commit = $matches[2];
mkdir("./backup");
$html .= "<br>backup folder created!";
$d_dir = data_path("cache");
//This should empty the /data/cache/ folder.
if (is_dir($d_dir)) {
$objects = scandir($d_dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($d_dir."/".$object) == "dir") rmdir($d_dir."/".$object); else unlink($d_dir."/".$object);
}
}
reset($objects);
$html .= "<br>data folder emptied!";
}
copy ("./data/config/shimmie.conf.php", "./backup/shimmie.conf.php");//Although this stays the same, will keep backup just incase.
$folders = array("./core", "./lib", "./themes", "./.htaccess", "./doxygen.conf", "./index.php", "./install.php", "./ext", "./contrib");
foreach($folders as $folder){
//TODO: Check MD5 of each file, don't rename if same.
rename ($folder, "./backup".substr($folder, 1)); //Move old files to backup
rename ("./".$matches[0].substr($folder, 1), $folder); //Move new files to main
}
$html .= "<br>old shimmie setup has been moved to /backup/ (excluding images/thumbs)!";
if (is_dir($matches[0])) {
$objects = scandir($matches[0]);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($matches[0]."/".$object) == "dir") rmdir($matches[0]."/".$object); else unlink($matches[0]."/".$object);
}
}
reset($objects);
rmdir($matches[0]);
$html .= "<br>".$matches[0]." deleted!";
}
$html .= "<br>shimmie updated (although you may have gotten errors, it should have worked!";
$html .= "<br>due to the way shimmie loads extensions, all optional extensions have been disabled";
$config->set_string("commit_hash", $commit);
$config->set_string("commit_time", $commitDateTime);
$html .= "<br>new commit_hash has been set!";
}
else {
$html .= "Error! Folder does not exist!?"; //Although this should be impossible, shall have it anyway.
}
}
elseif (file_exists($mfile)) { //#2
$zip = new ZipArchive;
if ($zip->open($mfile) === TRUE) {
$zip->extractTo('./');
$zip->close();
$html .= "extracted!";
$html .= "<br><a href='javascript:history.go(0)'>refresh</a> the page to continue!";
unlink($mfile); //Deletes master.zip
}
else {
$html .= "failed!";
}
}
else { //#1
//Taken from the upload ext.
transload($url, $mfile);
/** TODO: Backup all folders (except /data, /images, /thumbs) before attempting this?
Either that or point to https://github.com/shish/shimmie2/blob/master/README.txt -> Upgrade from 2.3.X **/
if(file_exists($mfile)) {
$html .= "downloaded!";
$html .= "<br><a href='javascript:history.go(0)'>refresh</a> the page to continue!";
}
else {
$html .= "download failed!";
$html .= "<br><a href='javascript:history.go(0)'>refresh</a> to try again!";
$html .= "<br>if you keep having this problem, you may have a problem with your transload engine!";
$zip = new ZipArchive;
if ($zip->open("./data/update_$commitSHA.zip") === TRUE) {
for($i = 1; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
if(substr($filename, -1) !== "/"){
copy("zip://".dirname(dirname(__DIR__)).'/'."./data/update_$commitSHA.zip"."#".$filename, substr($filename, 50));
}
}
$ok = TRUE; //TODO: Do proper checking to see if everything copied properly
}else{ log_warning("update", "Update failed to open ZIP."); }
$zip->close();
unlink("./data/update_$commitSHA.zip");
$config->set_bool("in_upgrade", FALSE);
if($ok){
$config->set_string("commit_hash", $commitSHA);
$config->set_string("update_time", date('d-m-Y'));
log_info("update", "Update succeeded?");
}
$page->add_block(new Block("Update", $html));
return $ok;
}
}

14
ext/update/script.js Normal file
View File

@ -0,0 +1,14 @@
$(function() {
if($('#updatecheck').length !== 0){
$.getJSON('https://api.github.com/repos/shish/shimmie2/commits', function(data){
var c = data[0];
$('#updatecheck').html('<a href="'+c['html_url']+'">'+c['sha']+'</a>' + " ("+c['commit']['message']+")");
var params = $.param({sha: c['sha'], date: c['commit']['committer']['date']});
$('#updatelink').attr('href', function(i, val){ return val + "?" + params; });
$('#updatelink').text("Update");
}).fail(function(){
$('#updatecheck').text("Loading failed. (Github down?)");
});
}
});

14
ext/update/theme.php Normal file
View File

@ -0,0 +1,14 @@
<?php
class UpdateTheme extends Themelet {
public function display_admin_block(){
global $page, $config;
$html = "".
"<b>Current Commit</b>: ".$config->get_string('commit_hash')." | (".$config->get_string('update_time').")".
"<br><b>Latest Commit</b>: <span id='updatecheck'>Loading...</span>".
"<br><a href='" . make_link('update/download') . "' id='updatelink'></a>";
//TODO: Show warning before use.
$page->add_block(new Block("Software Update", $html, "main", 75));
}
}
?>

4
lib/jquery-1.11.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
.ac_results{padding:0;border:1px solid black;background-color:white;overflow:hidden;z-index:99999}.ac_results ul{width:100%;list-style-position:outside;list-style:none;padding:0;margin:0}.ac_results li{margin:0;padding:2px 5px;cursor:default;display:block;font:menu;font-size:12px;line-height:16px;overflow:hidden}.ac_loading{background:white url('indicator.gif') right center no-repeat}.ac_odd{background-color:#eee}.ac_over{background-color:#0a246a;color:white}

File diff suppressed because one or more lines are too long

7
lib/jquery.autocomplete-2.4.4.min.css vendored Normal file
View File

@ -0,0 +1,7 @@
/**
* @fileOverview CSS for jquery-autocomplete, the jQuery Autocompleter
* @author <a href="mailto:dylan@dyve.net">Dylan Verheul</a>
* @license MIT | GPL | Apache 2.0, see LICENSE.txt
* @see https://github.com/dyve/jquery-autocomplete
*/
.acResults{padding:0;border:1px solid WindowFrame;background-color:Window;overflow:hidden}.acResults ul{margin:0;padding:0;list-style-position:outside;list-style:none}.acResults ul li{margin:0;padding:2px 5px;cursor:pointer;display:block;font:menu;font-size:12px;overflow:hidden}.acLoading{background:url(indicator.gif) right center no-repeat}.acSelect{background-color:Highlight;color:HighlightText}

9
lib/jquery.autocomplete-2.4.4.min.js vendored Normal file

File diff suppressed because one or more lines are too long

8
lib/jquery.cookie-1.4.0.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
/*!
* jQuery Cookie Plugin v1.4.0
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2013 Klaus Hartl
* Released under the MIT license
*/
(function(e){if(typeof define==="function"&&define.amd){define(["jquery"],e)}else{e(jQuery)}})(function(e){function n(e){return u.raw?e:encodeURIComponent(e)}function r(e){return u.raw?e:decodeURIComponent(e)}function i(e){return n(u.json?JSON.stringify(e):String(e))}function s(e){if(e.indexOf('"')===0){e=e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\")}try{e=decodeURIComponent(e.replace(t," "))}catch(n){return}try{return u.json?JSON.parse(e):e}catch(n){}}function o(t,n){var r=u.raw?t:s(t);return e.isFunction(n)?n(r):r}var t=/\+/g;var u=e.cookie=function(t,s,a){if(s!==undefined&&!e.isFunction(s)){a=e.extend({},u.defaults,a);if(typeof a.expires==="number"){var f=a.expires,l=a.expires=new Date;l.setDate(l.getDate()+f)}return document.cookie=[n(t),"=",i(s),a.expires?"; expires="+a.expires.toUTCString():"",a.path?"; path="+a.path:"",a.domain?"; domain="+a.domain:"",a.secure?"; secure":""].join("")}var c=t?undefined:{};var h=document.cookie?document.cookie.split("; "):[];for(var p=0,d=h.length;p<d;p++){var v=h[p].split("=");var m=r(v.shift());var g=v.join("=");if(t&&t===m){c=o(g,s);break}if(!t&&(g=o(g))!==undefined){c[m]=g}}return c};u.defaults={};e.removeCookie=function(t,n){if(e.cookie(t)!==undefined){e.cookie(t,"",e.extend({},n,{expires:-1}));return true}return false}});

View File

@ -1 +0,0 @@
jQuery.cookie=function(b,j,m){if(typeof j!="undefined"){m=m||{};if(j===null){j="";m=$.extend({},m);m.expires=-1}var e="";if(m.expires&&(typeof m.expires=="number"||m.expires.toUTCString)){var f;if(typeof m.expires=="number"){f=new Date();f.setTime(f.getTime()+(m.expires*24*60*60*1000))}else{f=m.expires}e="; expires="+f.toUTCString()}var l=m.path?"; path="+(m.path):"";var g=m.domain?"; domain="+(m.domain):"";var a=m.secure?"; secure":"";document.cookie=[b,"=",encodeURIComponent(j),e,l,g,a].join("")}else{var d=null;if(document.cookie&&document.cookie!=""){var k=document.cookie.split(";");for(var h=0;h<k.length;h++){var c=jQuery.trim(k[h]);if(c.substring(0,b.length+1)==(b+"=")){d=decodeURIComponent(c.substring(b.length+1));break}}}return d}};

File diff suppressed because one or more lines are too long

2
lib/jquery.imgnotes-1.0.min.css vendored Normal file
View File

@ -0,0 +1,2 @@
/** imgnotes jQuery plugin v1.0.0 **/
.notesicon{background:url(notes.png) no-repeat #fff;overflow:hidden;position:absolute;height:27px;width:22px;z-index:1000000;cursor:pointer}.note{display:none;background:url(spacer.gif);border:2px solid #fff;overflow:hidden;position:absolute;z-index:0;cursor:default}.notep{display:none;background:#eee;font-size:8pt;margin-top:0;padding:2px;position:absolute;width:175px;cursor:default}#noteform{display:none;position:absolute;width:250px}#noteform textarea{width:100%}

15
lib/jquery.imgnotes-1.0.min.js vendored Normal file
View File

@ -0,0 +1,15 @@
/**
* imgnotes jQuery plugin
* version 1.0
*
* Copyright (c) 2008 - Dr. Tarique Sani <tarique@sanisoft.com>
*
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* @URL http://www.sanisoft.com/blog/2008/05/26/img-notes-jquery-plugin/
* @Example example.html
*
**/
(function(e){function t(){e(".note").hover(function(){e(".note").show();e(this).next(".notep").show();e(this).next(".notep").css("z-index",1e4)},function(){e(".note").show();e(this).next(".notep").hide();e(this).next(".notep").css("z-index",0)})}function n(t){note_left=parseInt(imgOffset.left)+parseInt(t.x1);note_top=parseInt(imgOffset.top)+parseInt(t.y1);note_p_top=note_top+parseInt(t.height)+5;note_area_div=e("<div class='note'></div>").css({left:note_left+"px",top:note_top+"px",width:t.width+"px",height:t.height+"px"});note_text_div=e('<div class="notep" >'+t.note+"</div>").css({left:note_left+"px",top:note_p_top+"px"});e("body").append(note_area_div);e("body").append(note_text_div)}function r(t){if(true!==t){return}notes_icon_left=parseInt(imgOffset.left)+parseInt(imgWidth)-36;notes_icon_top=parseInt(imgOffset.top)+parseInt(imgHieght)-40;notes_icon_div=note_area_div=e("<div class='notesicon'></div>").css({left:notes_icon_left+"px",top:notes_icon_top+"px"});e("body").append(notes_icon_div);e(".notesicon").toggle(function(){e.fn.imgNotes.showAll()},function(){e.fn.imgNotes.hideAll()})}e.fn.imgNotes=function(i){if(undefined==s){var s}if(undefined!=i.notes){s=i.notes}if(i.url){e.ajaxSetup({async:false});e.getJSON(i.url,function(e){s=e})}image=this;imgOffset=e(image).offset();imgHieght=e(image).height();imgWidth=e(image).width();e(s).each(function(){n(this)});e(image).hover(function(){e(".note").show()},function(){e(".note").hide();e(".notep").hide()});t();r(i.isMobile);e(window).resize(function(){e(".note").remove();e(".notep").remove();e(".notesicon").remove();imgOffset=e(image).offset();imgHieght=e(image).height();imgWidth=e(image).width();e(s).each(function(){n(this)});t();r(i.isMobile)})};e.fn.imgNotes.showAll=function(){e(".note").show();e(".notep").show()};e.fn.imgNotes.hideAll=function(){e(".note").hide();e(".notep").hide()}})(jQuery);

View File

@ -1,15 +0,0 @@
/*
* Lazy Load - jQuery plugin for lazy loading images
*
* Copyright (c) 2007-2012 Mika Tuupola
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*
* Project home:
* http://www.appelsiini.net/projects/lazyload
*
* Version: 1.7.2
*
*/
(function(a,b){$window=a(b),a.fn.lazyload=function(c){function f(){var b=0;d.each(function(){var c=a(this);if(e.skip_invisible&&!c.is(":visible"))return;if(!a.abovethetop(this,e)&&!a.leftofbegin(this,e))if(!a.belowthefold(this,e)&&!a.rightoffold(this,e))c.trigger("appear");else if(++b>e.failure_limit)return!1})}var d=this,e={threshold:0,failure_limit:0,event:"scroll",effect:"show",container:b,data_attribute:"original",skip_invisible:!0,appear:null,load:null};return c&&(undefined!==c.failurelimit&&(c.failure_limit=c.failurelimit,delete c.failurelimit),undefined!==c.effectspeed&&(c.effect_speed=c.effectspeed,delete c.effectspeed),a.extend(e,c)),$container=e.container===undefined||e.container===b?$window:a(e.container),0===e.event.indexOf("scroll")&&$container.bind(e.event,function(a){return f()}),this.each(function(){var b=this,c=a(b);b.loaded=!1,c.one("appear",function(){if(!this.loaded){if(e.appear){var f=d.length;e.appear.call(b,f,e)}a("<img />").bind("load",function(){c.hide().attr("src",c.data(e.data_attribute))[e.effect](e.effect_speed),b.loaded=!0;var f=a.grep(d,function(a){return!a.loaded});d=a(f);if(e.load){var g=d.length;e.load.call(b,g,e)}}).attr("src",c.data(e.data_attribute))}}),0!==e.event.indexOf("scroll")&&c.bind(e.event,function(a){b.loaded||c.trigger("appear")})}),$window.bind("resize",function(a){f()}),f(),this},a.belowthefold=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.height()+$window.scrollTop():e=$container.offset().top+$container.height(),e<=a(c).offset().top-d.threshold},a.rightoffold=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.width()+$window.scrollLeft():e=$container.offset().left+$container.width(),e<=a(c).offset().left-d.threshold},a.abovethetop=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.scrollTop():e=$container.offset().top,e>=a(c).offset().top+d.threshold+a(c).height()},a.leftofbegin=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.scrollLeft():e=$container.offset().left,e>=a(c).offset().left+d.threshold+a(c).width()},a.inviewport=function(b,c){return!a.rightofscreen(b,c)&&!a.leftofscreen(b,c)&&!a.belowthefold(b,c)&&!a.abovethetop(b,c)},a.extend(a.expr[":"],{"below-the-fold":function(c){return a.belowthefold(c,{threshold:0,container:b})},"above-the-top":function(c){return!a.belowthefold(c,{threshold:0,container:b})},"right-of-screen":function(c){return a.rightoffold(c,{threshold:0,container:b})},"left-of-screen":function(c){return!a.rightoffold(c,{threshold:0,container:b})},"in-viewport":function(c){return!a.inviewport(c,{threshold:0,container:b})},"above-the-fold":function(c){return!a.belowthefold(c,{threshold:0,container:b})},"right-of-fold":function(c){return a.rightoffold(c,{threshold:0,container:b})},"left-of-fold":function(c){return!a.rightoffold(c,{threshold:0,container:b})}})})(jQuery,window);

View File

@ -1,386 +0,0 @@
/*
* imgAreaSelect jQuery plugin
* version 0.4
*
* Copyright (c) 2008 Michal Wojciechowski (odyniec.net)
*
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* http://odyniec.net/projects/imgareaselect/
*
*/
jQuery.imgAreaSelect = function (img, options) {
var $area = jQuery('<div></div>'),
$border1 = jQuery('<div></div>'),
$border2 = jQuery('<div></div>'),
$outLeft = jQuery('<div></div>'),
$outTop = jQuery('<div></div>'),
$outRight = jQuery('<div></div>'),
$outBottom = jQuery('<div></div>'),
imgOfs, imgWidth, imgHeight,
zIndex = 0, fixed = false,
startX, startY, moveX, moveY,
resizeMargin = 10, resize = [ ], V = 0, H = 1,
d, aspectRatio,
x1, x2, y1, y2, x, y,
selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 };
var $a = $area.add($border1).add($border2);
var $o = $outLeft.add($outTop).add($outRight).add($outBottom);
function getZIndex()
{
var $p = jQuery(img);
while ($p.length && !$p.is('body')) {
if (!isNaN($p.css('z-index')) && $p.css('z-index') > zIndex)
zIndex = $p.css('z-index');
if ($p.css('position') == 'fixed') fixed = true;
$p = $p.parent();
}
}
function areaMouseMove(event)
{
x = event.pageX - selection.x1 - imgOfs.left;
y = event.pageY - selection.y1 - imgOfs.top;
resize = [ ];
if (options.resizable) {
if (y <= resizeMargin)
resize[V] = 'n';
else if (y >= selection.height - resizeMargin)
resize[V] = 's';
if (x <= resizeMargin)
resize[H] = 'w';
else if (x >= selection.width - resizeMargin)
resize[H] = 'e';
}
$border2.css('cursor', resize.length ? resize.join('') + '-resize' :
options.movable ? 'move' : '');
}
function areaMouseDown(event)
{
if (event.which != 1) return false;
if (options.resizable && resize.length > 0) {
jQuery('body').css('cursor', resize.join('') + '-resize');
x1 = (resize[H] == 'w' ? selection.x2 : selection.x1) + imgOfs.left;
y1 = (resize[V] == 'n' ? selection.y2 : selection.y1) + imgOfs.top;
jQuery(document).mousemove(selectingMouseMove);
$border2.unbind('mousemove', areaMouseMove);
jQuery(document).one('mouseup', function () {
resize = [ ];
jQuery('body').css('cursor', '');
if (options.autoHide)
$a.hide();
options.onSelectEnd(img, selection);
jQuery(document).unbind('mousemove', selectingMouseMove);
$border2.mousemove(areaMouseMove);
});
}
else if (options.movable) {
moveX = selection.x1 + imgOfs.left;
moveY = selection.y1 + imgOfs.top;
startX = event.pageX;
startY = event.pageY;
jQuery(document)
.mousemove(movingMouseMove)
.one('mouseup', function () {
options.onSelectEnd(img, selection);
jQuery(document).unbind('mousemove', movingMouseMove);
});
}
else
jQuery(img).mousedown(event);
return false;
}
function aspectRatioXY()
{
x2 = Math.max(imgOfs.left, Math.min(imgOfs.left + imgWidth,
x1 + Math.abs(y2 - y1) * aspectRatio * (x2 > x1 ? 1 : -1)));
y2 = Math.round(Math.max(imgOfs.top, Math.min(imgOfs.top + imgHeight,
y1 + Math.abs(x2 - x1) / aspectRatio * (y2 > y1 ? 1 : -1))));
x2 = Math.round(x2);
}
function aspectRatioYX()
{
y2 = Math.max(imgOfs.top, Math.min(imgOfs.top + imgHeight,
y1 + Math.abs(x2 - x1) / aspectRatio * (y2 > y1 ? 1 : -1)));
x2 = Math.round(Math.max(imgOfs.left, Math.min(imgOfs.left + imgWidth,
x1 + Math.abs(y2 - y1) * aspectRatio * (x2 > x1 ? 1 : -1))));
y2 = Math.round(y2);
}
function selectingMouseMove(event)
{
x2 = !resize.length || resize[H] || aspectRatio ? event.pageX : selection.x2 + imgOfs.left;
y2 = !resize.length || resize[V] || aspectRatio ? event.pageY : selection.y2 + imgOfs.top;
if (options.minWidth && Math.abs(x2 - x1) < options.minWidth) {
x2 = x1 - options.minWidth * (x2 < x1 ? 1 : -1);
if (x2 < imgOfs.left)
x1 = imgOfs.left + options.minWidth;
else if (x2 > imgOfs.left + imgWidth)
x1 = imgOfs.left + imgWidth - options.minWidth;
}
if (options.minHeight && Math.abs(y2 - y1) < options.minHeight) {
y2 = y1 - options.minHeight * (y2 < y1 ? 1 : -1);
if (y2 < imgOfs.top)
y1 = imgOfs.top + options.minHeight;
else if (y2 > imgOfs.top + imgHeight)
y1 = imgOfs.top + imgHeight - options.minHeight;
}
x2 = Math.max(imgOfs.left, Math.min(x2, imgOfs.left + imgWidth));
y2 = Math.max(imgOfs.top, Math.min(y2, imgOfs.top + imgHeight));
if (aspectRatio)
if (Math.abs(x2 - x1) / aspectRatio > Math.abs(y2 - y1))
aspectRatioYX();
else
aspectRatioXY();
if (options.maxWidth && Math.abs(x2 - x1) > options.maxWidth) {
x2 = x1 - options.maxWidth * (x2 < x1 ? 1 : -1);
if (aspectRatio) aspectRatioYX();
}
if (options.maxHeight && Math.abs(y2 - y1) > options.maxHeight) {
y2 = y1 - options.maxHeight * (y2 < y1 ? 1 : -1);
if (aspectRatio) aspectRatioXY();
}
selection.x1 = Math.min(x1, x2) - imgOfs.left;
selection.x2 = Math.max(x1, x2) - imgOfs.left;
selection.y1 = Math.min(y1, y2) - imgOfs.top;
selection.y2 = Math.max(y1, y2) - imgOfs.top;
selection.width = Math.abs(x2 - x1);
selection.height = Math.abs(y2 - y1);
$a.css({
left: (selection.x1 + imgOfs.left) + 'px',
top: (selection.y1 + imgOfs.top) + 'px',
width: Math.max(selection.width - options.borderWidth * 2, 0) + 'px',
height: Math.max(selection.height - options.borderWidth * 2, 0) + 'px'
});
$outLeft.css({ width: selection.x1 + 'px' });
$outTop.css({ left: imgOfs.left + selection.x1 + 'px', width: selection.width + 'px',
height: selection.y1 + 'px' });
$outRight.css({ left: imgOfs.left + selection.x2 + 'px', width: imgWidth - selection.x2 + 'px' });
$outBottom.css({ left: imgOfs.left + selection.x1 + 'px', top: imgOfs.top + selection.y2 + 'px',
width: selection.width + 'px', height: imgHeight - selection.y2 + 'px' });
options.onSelectChange(img, selection);
return false;
}
function movingMouseMove(event)
{
x1 = Math.max(imgOfs.left, Math.min(moveX + event.pageX - startX,
imgOfs.left + imgWidth - selection.width));
y1 = Math.max(imgOfs.top, Math.min(moveY + event.pageY - startY,
imgOfs.top + imgHeight - selection.height));
x2 = x1 + selection.width;
y2 = y1 + selection.height;
selection.x1 = x1 - imgOfs.left;
selection.y1 = y1 - imgOfs.top;
selection.x2 = x2 - imgOfs.left;
selection.y2 = y2 - imgOfs.top;
$a.css({
left: x1 + 'px',
top: y1 + 'px',
width: Math.max(x2 - x1 - options.borderWidth * 2, 0) + 'px',
height: Math.max(y2 - y1 - options.borderWidth * 2, 0) + 'px'
});
$outLeft.css({ width: selection.x1 + 'px' });
$outTop.css({ left: imgOfs.left + selection.x1 + 'px', width: selection.width + 'px',
height: selection.y1 + 'px' });
$outRight.css({ left: imgOfs.left + selection.x2 + 'px', width: imgWidth - selection.x2 + 'px' });
$outBottom.css({ left: imgOfs.left + selection.x1 + 'px', top: imgOfs.top + selection.y2 + 'px',
width: selection.width + 'px', height: imgHeight - selection.y2 + 'px' });
options.onSelectChange(img, selection);
event.preventDefault();
return false;
}
function imgMouseDown(event)
{
if (event.which != 1) return false;
startX = x1 = event.pageX;
startY = y1 = event.pageY;
resize = [ ];
$a.css({ width: '0px', height: '0px', left: x1, top: y1 });
$outLeft.css({ width: x1 - imgOfs.left + 'px' });
$outTop.css({ left: x1 + 'px', height: y1 - imgOfs.top + 'px', width: '0px' });
$outRight.css({ left: x1 + 'px', width: imgOfs.left + imgWidth - x1 + 'px' });
$outBottom.css({ left: x1 + 'px', top: y1 + 'px', width: '0px', height: imgOfs.top + imgHeight - y1 + 'px' });
$a.add($o).show();
jQuery(document).mousemove(selectingMouseMove);
$border2.unbind('mousemove', areaMouseMove);
selection.x1 = selection.x2 = x1 - imgOfs.left;
selection.y1 = selection.y2 = y1 - imgOfs.top;
options.onSelectStart(img, selection);
jQuery(document).one('mouseup', function () {
if (options.autoHide)
$a.add($o).hide();
options.onSelectEnd(img, selection);
jQuery(document).unbind('mousemove', selectingMouseMove);
$border2.mousemove(areaMouseMove);
});
return false;
}
this.setOptions = function(newOptions)
{
options = jQuery.extend(options, newOptions);
if (newOptions.x1 != null) {
x1 = (selection.x1 = newOptions.x1) + imgOfs.left;
y1 = (selection.y1 = newOptions.y1) + imgOfs.top;
x2 = (selection.x2 = newOptions.x2) + imgOfs.left;
y2 = (selection.y2 = newOptions.y2) + imgOfs.top;
selection.width = x2 - x1;
selection.height = y2 - y1;
$a.css({
left: x1 + 'px',
top: y1 + 'px',
width: Math.max(x2 - x1 - options.borderWidth * 2, 0) + 'px',
height: Math.max(y2 - y1 - options.borderWidth * 2, 0) + 'px'
});
$outLeft.css({ width: selection.x1 + 'px' });
$outTop.css({ left: x1 + 'px', width: selection.width + 'px', height: selection.y1 + 'px' });
$outRight.css({ left: x2 + 'px', width: (imgWidth - selection.x2) + 'px' });
$outBottom.css({ left: x1 + 'px', top: y2 + 'px', width: selection.width + 'px', height: (imgHeight - selection.y2) + 'px' });
$a.add($o).show();
options.onSelectChange(img, selection);
}
if (newOptions.hide) {
$a.hide();
$outLeft.hide();
$outRight.hide();
$outTop.hide();
$outBottom.hide();
} else if (newOptions.show) {
$a.show();
$outLeft.hide();
$outRight.hide();
$outTop.hide();
$outBottom.hide();
}
$a.css({ borderWidth: options.borderWidth + 'px' });
$area.css({ backgroundColor: options.selectionColor, opacity: options.selectionOpacity });
$border1.css({ borderStyle: 'solid', borderColor: options.borderColor1 });
$border2.css({ borderStyle: 'dashed', borderColor: options.borderColor2 });
$o.css({ opacity: options.outerOpacity, backgroundColor: options.outerColor });
aspectRatio = options.aspectRatio && (d = options.aspectRatio.split(/:/)) ?
d[0] / d[1] : null;
if (options.disable || options.enable === false) {
$a.unbind('mousemove', areaMouseMove).unbind('mousedown', areaMouseDown);
jQuery(img).add($o).unbind('mousedown', imgMouseDown);
}
else if (options.enable || options.disable === false) {
if (options.resizable || options.movable)
$a.mousemove(areaMouseMove).mousedown(areaMouseDown);
//jQuery(img).add($o).mousedown(imgMouseDown);
}
options.enable = options.disable = undefined;
};
imgWidth = jQuery(img).width();
imgHeight = jQuery(img).height();
imgOfs = jQuery(img).offset();
if (jQuery.browser.msie)
jQuery(img).attr('unselectable', 'on');
getZIndex();
$a.add($o).css({ display: 'none', position: fixed ? 'fixed' : 'absolute', overflow: 'hidden', zIndex: zIndex });
$area.css({ borderStyle: 'solid' });
$outLeft.css({ left: imgOfs.left + 'px', top: imgOfs.top + 'px', height: imgHeight + 'px' });
$outTop.css({ top: imgOfs.top + 'px' });
$outRight.css({ top: imgOfs.top + 'px', height: imgHeight + 'px' });
jQuery('body').append($o);
jQuery('body').append($a);
initOptions = {
borderColor1: '#000',
borderColor2: '#fff',
borderWidth: 1,
movable: true,
resizable: true,
selectionColor: '#fff',
selectionOpacity: 0.2,
outerColor: '#000',
outerOpacity: 0.2,
onSelectStart: function () {},
onSelectChange: function () {},
onSelectEnd: function () {}
};
options = jQuery.extend(initOptions, options);
this.setOptions(options);
};
jQuery.fn.imgAreaSelect = function (options) {
options = options || {};
this.each(function () {
if (jQuery(this).data('imgAreaSelect')){
jQuery(this).data('imgAreaSelect').setOptions(options);
} else {
if (options.enable === undefined && options.disable === undefined)
options.enable = true;
jQuery(this).data('imgAreaSelect', new jQuery.imgAreaSelect(this, options));
}
});
return this;
};

View File

@ -1,91 +0,0 @@
/**
* imgnotes jQuery plugin
* version 0.1
*
* Copyright (c) 2008 Dr. Tarique Sani <tarique@sanisoft.com>
*
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* @URL http://www.sanisoft.com/blog/2008/05/26/img-notes-jquery-plugin/
* @Example example.html
*
**/
//Wrap in a closure
(function($) {
$.fn.imgNotes = function(n) {
if(undefined != n){
notes = n;
}
image = this;
imgOffset = $(image).offset();
$(notes).each(function(){
appendnote(this);
});
$(image).hover(
function(){
$('.note').show();
},
function(){
$('.note').hide();
}
);
addnoteevents();
$(window).resize(function () {
$('.note').remove();
imgOffset = $(image).offset();
$(notes).each(function(){
appendnote(this);
});
addnoteevents();
});
}
function addnoteevents() {
$('.note').hover(
function(){
$('.note').show();
$(this).next('.notep').show();
$(this).next('.notep').css("z-index", 10000);
},
function(){
$('.note').show();
$(this).next('.notep').hide();
$(this).next('.notep').css("z-index", 0);
}
);
}
function appendnote(note_data){
note_left = parseInt(imgOffset.left) + parseInt(note_data.x1);
note_top = parseInt(imgOffset.top) + parseInt(note_data.y1);
note_p_top = note_top + parseInt(note_data.height)+5;
note_area_div = $("<div class='note'></div>").css({ left: note_left + 'px', top: note_top + 'px', width: note_data.width + 'px', height: note_data.height + 'px' });
note_text_div = $('<div class="notep" >'+ note_data.note.replace(/([^>]?)\n/g, '$1<br />\n') + '</div>').css({ left: note_left + 'px', top: note_p_top + 'px'});
//added by alpha
note_id_div = $('<div class="noteID" >'+note_data.note_id+'</div>').css({ left: note_left + 'px', top: note_p_top + 'px'}).hide();
$('body').append(note_area_div);
$('body').append(note_text_div);
//added by alpha
$('body').append(note_id_div);
}
// End the closure
})(jQuery);

2
lib/jquery.tablesorter-2.0.5.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,189 +0,0 @@
/**
* Timeago is a jQuery plugin that makes it easy to support automatically
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
*
* @name timeago
* @version 1.1.0
* @requires jQuery v1.2.3+
* @author Ryan McGeary
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
*
* For usage and examples, visit:
* http://timeago.yarp.com/
*
* Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.timeago = function(timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else if (typeof timestamp === "number") {
return inWords(new Date(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;
$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowFuture: false,
localeTitle: false,
cutoff: 0,
strings: {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: "ago",
suffixFromNow: "from now",
seconds: "less than a minute",
minute: "about a minute",
minutes: "%d minutes",
hour: "about an hour",
hours: "about %d hours",
day: "a day",
days: "%d days",
month: "about a month",
months: "%d months",
year: "about a year",
years: "%d years",
wordSeparator: " ",
numbers: []
}
},
inWords: function(distanceMillis) {
var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
}
var seconds = Math.abs(distanceMillis) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;
function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
seconds < 90 && substitute($l.minute, 1) ||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
minutes < 90 && substitute($l.hour, 1) ||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
hours < 42 && substitute($l.day, 1) ||
days < 30 && substitute($l.days, Math.round(days)) ||
days < 45 && substitute($l.month, 1) ||
days < 365 && substitute($l.months, Math.round(days / 30)) ||
years < 1.5 && substitute($l.year, 1) ||
substitute($l.years, Math.round(years));
var separator = $l.wordSeparator || "";
if ($l.wordSeparator === undefined) { separator = " "; }
return $.trim([prefix, words, suffix].join(separator));
},
parse: function(iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
s = s.replace(/T/," ").replace(/Z/," UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
return new Date(s);
},
datetime: function(elem) {
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
},
isTime: function(elem) {
// jQuery's `is()` doesn't play well with HTML5 in IE
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
}
});
// functions that can be called via $(el).timeago('action')
// init is default when no action is given
// functions are called with context of a single element
var functions = {
init: function(){
var refresh_el = $.proxy(refresh, this);
refresh_el();
var $s = $t.settings;
if ($s.refreshMillis > 0) {
setInterval(refresh_el, $s.refreshMillis);
}
},
update: function(time){
$(this).data('timeago', { datetime: $t.parse(time) });
refresh.apply(this);
}
};
$.fn.timeago = function(action, options) {
var fn = action ? functions[action] : functions.init;
if(!fn){
throw new Error("Unknown function name '"+ action +"' for timeago");
}
// each over objects here and call the requested function
this.each(function(){
fn.call(this, options);
});
return this;
};
function refresh() {
var data = prepareData(this);
var $s = $t.settings;
if (!isNaN(data.datetime)) {
if ( $s.cutoff == 0 || distance(data.datetime) < $s.cutoff) {
$(this).text(inWords(data.datetime));
}
}
return this;
}
function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", { datetime: $t.datetime(element) });
var text = $.trim(element.text());
if ($t.settings.localeTitle) {
element.attr("title", element.data('timeago').datetime.toLocaleString());
} else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
element.attr("title", text);
}
}
return element.data("timeago");
}
function inWords(date) {
return $t.inWords(distance(date));
}
function distance(date) {
return (new Date().getTime() - date.getTime());
}
// fix for IE6 suckage
document.createElement("abbr");
document.createElement("time");
}));

17
lib/jquery.timeago-1.3.1.min.js vendored Normal file
View File

@ -0,0 +1,17 @@
/**
* Timeago is a jQuery plugin that makes it easy to support automatically
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
*
* @name timeago
* @version 1.3.1
* @requires jQuery v1.2.3+
* @author Ryan McGeary
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
*
* For usage and examples, visit:
* http://timeago.yarp.com/
*
* Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/
(function(e){if(typeof define==="function"&&define.amd){define(["jquery"],e)}else{e(jQuery)}})(function(e){function r(){var n=i(this);var r=t.settings;if(!isNaN(n.datetime)){if(r.cutoff==0||o(n.datetime)<r.cutoff){e(this).text(s(n.datetime))}}return this}function i(n){n=e(n);if(!n.data("timeago")){n.data("timeago",{datetime:t.datetime(n)});var r=e.trim(n.text());if(t.settings.localeTitle){n.attr("title",n.data("timeago").datetime.toLocaleString())}else if(r.length>0&&!(t.isTime(n)&&n.attr("title"))){n.attr("title",r)}}return n.data("timeago")}function s(e){return t.inWords(o(e))}function o(e){return(new Date).getTime()-e.getTime()}e.timeago=function(t){if(t instanceof Date){return s(t)}else if(typeof t==="string"){return s(e.timeago.parse(t))}else if(typeof t==="number"){return s(new Date(t))}else{return s(e.timeago.datetime(t))}};var t=e.timeago;e.extend(e.timeago,{settings:{refreshMillis:6e4,allowFuture:false,localeTitle:false,cutoff:0,strings:{prefixAgo:null,prefixFromNow:null,suffixAgo:"ago",suffixFromNow:"from now",seconds:"less than a minute",minute:"about a minute",minutes:"%d minutes",hour:"about an hour",hours:"about %d hours",day:"a day",days:"%d days",month:"about a month",months:"%d months",year:"about a year",years:"%d years",wordSeparator:" ",numbers:[]}},inWords:function(t){function l(r,i){var s=e.isFunction(r)?r(i,t):r;var o=n.numbers&&n.numbers[i]||i;return s.replace(/%d/i,o)}var n=this.settings.strings;var r=n.prefixAgo;var i=n.suffixAgo;if(this.settings.allowFuture){if(t<0){r=n.prefixFromNow;i=n.suffixFromNow}}var s=Math.abs(t)/1e3;var o=s/60;var u=o/60;var a=u/24;var f=a/365;var c=s<45&&l(n.seconds,Math.round(s))||s<90&&l(n.minute,1)||o<45&&l(n.minutes,Math.round(o))||o<90&&l(n.hour,1)||u<24&&l(n.hours,Math.round(u))||u<42&&l(n.day,1)||a<30&&l(n.days,Math.round(a))||a<45&&l(n.month,1)||a<365&&l(n.months,Math.round(a/30))||f<1.5&&l(n.year,1)||l(n.years,Math.round(f));var h=n.wordSeparator||"";if(n.wordSeparator===undefined){h=" "}return e.trim([r,c,i].join(h))},parse:function(t){var n=e.trim(t);n=n.replace(/\.\d+/,"");n=n.replace(/-/,"/").replace(/-/,"/");n=n.replace(/T/," ").replace(/Z/," UTC");n=n.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2");return new Date(n)},datetime:function(n){var r=t.isTime(n)?e(n).attr("datetime"):e(n).attr("title");return t.parse(r)},isTime:function(t){return e(t).get(0).tagName.toLowerCase()==="time"}});var n={init:function(){var n=e.proxy(r,this);n();var i=t.settings;if(i.refreshMillis>0){setInterval(n,i.refreshMillis)}},update:function(n){e(this).data("timeago",{datetime:t.parse(n)});r.apply(this)}};e.fn.timeago=function(e,t){var r=e?n[e]:n.init;if(!r){throw new Error("Unknown function name '"+e+"' for timeago")}this.each(function(){r.call(this,t)});return this};document.createElement("abbr");document.createElement("time")})

File diff suppressed because one or more lines are too long

4
lib/modernizr-2.7.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,8 @@ $(document).ready(function() {
jQuery.timeago.settings.cutoff = 365 * dayMS;
$("time").timeago();
//TODO: Possibly move to using TextExtJS for autocomplete? - http://textextjs.com/
// Also use autocomplete in tag box?
$('.autocomplete_tags').autocomplete(base_href + '/api/internal/tag_list/complete', {
width: 320,
max: 15,
@ -13,12 +15,10 @@ $(document).ready(function() {
multipleSeparator: ' ',
scroll: true,
scrollHeight: 300,
selectFirst: false
});
$("IMG.lazy").show().lazyload({
//effect: "fadeIn",
threshold: 200
selectFirst: false,
queryParamName: 's',
delay: 150,
minChars: 1
});
$("TABLE.sortable").tablesorter();

BIN
lib/spacer.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

View File

@ -1,26 +1,5 @@
<?php
class Themelet extends BaseThemelet {
public function build_thumb_html(Image $image) {
global $config;
$h_view_link = make_link("post/view/{$image->id}");
$h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip());
$i_id = int_escape($image->id);
$h_tags = strtolower($image->get_tag_list());
// If file is flash or svg then sets thumbnail to max size.
if($image->ext == 'swf' || $image->ext == 'svg') {
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
}
else{
$tsize = get_thumbnail_size($image->width, $image->height);
}
return "<a href='$h_view_link' class='shm-thumb shm-thumb-link' data-tags='$h_tags' data-post-id='$i_id'><img title='$h_tip' alt='$h_tip' ".
"width='{$tsize[0]}' height='{$tsize[1]}' src='$h_thumb_link' /></a>";
}
public function display_paginator(Page $page, $base, $query, $page_number, $total_pages) {
if($total_pages == 0) $total_pages = 1;
$body = $this->build_paginator($page_number, $total_pages, $base, $query);
@ -42,7 +21,7 @@ class Themelet extends BaseThemelet {
private function build_paginator($current_page, $total_pages, $base_url, $query) {
$next = $current_page + 1;
$prev = $current_page - 1;
$rand = rand(1, $total_pages);
$rand = mt_rand(1, $total_pages);
$at_start = ($current_page <= 3 || $total_pages <= 3);
$at_end = ($current_page >= $total_pages -2);

View File

@ -1,26 +1,5 @@
<?php
class Themelet extends BaseThemelet {
public function build_thumb_html(Image $image) {
global $config;
$h_view_link = make_link("post/view/{$image->id}");
$h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip());
$i_id = int_escape($image->id);
$h_tags = strtolower($image->get_tag_list());
// If file is flash or svg then sets thumbnail to max size.
if($image->ext == 'swf' || $image->ext == 'svg') {
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
}
else{
$tsize = get_thumbnail_size($image->width, $image->height);
}
return "<a href='$h_view_link' class='shm-thumb shm-thumb-link' data-tags='$h_tags' data-post-id='$i_id'><img title='$h_tip' alt='$h_tip' ".
"width='{$tsize[0]}' height='{$tsize[1]}' src='$h_thumb_link' /></a>";
}
public function display_paginator(Page $page, $base, $query, $page_number, $total_pages) {
if($total_pages == 0) $total_pages = 1;
$body = $this->build_paginator($page_number, $total_pages, $base, $query);
@ -42,7 +21,7 @@ class Themelet extends BaseThemelet {
private function build_paginator($current_page, $total_pages, $base_url, $query) {
$next = $current_page + 1;
$prev = $current_page - 1;
$rand = rand(1, $total_pages);
$rand = mt_rand(1, $total_pages);
$at_start = ($current_page <= 3 || $total_pages <= 3);
$at_end = ($current_page >= $total_pages -2);

View File

@ -1,30 +1,5 @@
<?php
class Themelet extends BaseThemelet {
/**
* Generic thumbnail code; returns HTML rather than adding
* a block since thumbs tend to go inside blocks...
*/
public function build_thumb_html(Image $image) {
global $config;
$h_view_link = make_link("post/view/{$image->id}");
$h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip());
$i_id = int_escape($image->id);
$h_tags = strtolower($image->get_tag_list());
// If file is flash or svg then sets thumbnail to max size.
if($image->ext == 'swf' || $image->ext == 'svg') {
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
}
else {
$tsize = get_thumbnail_size($image->width, $image->height);
}
return "<a href='$h_view_link' class='thumb shm-thumb shm-thumb-link' data-tags='$h_tags' data-post-id='$i_id'><img title='$h_tip' alt='$h_tip' ".
"width='{$tsize[0]}' height='{$tsize[1]}' src='$h_thumb_link' /></a>";
}
/**
* Add a generic paginator
*/
@ -50,7 +25,7 @@ class Themelet extends BaseThemelet {
private function build_paginator($current_page, $total_pages, $base_url, $query) {
$next = $current_page + 1;
$prev = $current_page - 1;
$rand = rand(1, $total_pages);
$rand = mt_rand(1, $total_pages);
$at_start = ($current_page <= 1 || $total_pages <= 1);
$at_end = ($current_page >= $total_pages);

View File

@ -1,34 +1,5 @@
<?php
class Themelet extends BaseThemelet {
/**
* Generic thumbnail code; returns HTML rather than adding
* a block since thumbs tend to go inside blocks...
*/
public function build_thumb_html(Image $image) {
global $config;
$i_id = (int) $image->id;
$h_view_link = make_link('post/view/'.$i_id);
$h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip());
$h_tags = strtolower($image->get_tag_list());
$base = get_base_href();
// If file is flash or svg then sets thumbnail to max size.
if($image->ext === 'swf' || $image->ext === 'svg'){
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
}
else{
$tsize = get_thumbnail_size($image->width, $image->height);
}
return '<center class="shm-thumb" data-tags="'.$h_tags.'" data-post-id="'.$i_id.'"><div class="thumbblock">'.
'<a href="'.$h_view_link.'" class="thumb shm-thumb-link">'.
'<img id="thumb_'.$i_id.'" title="'.$h_tip.'" alt="'.$h_tip.'" height="'.$tsize[1].'" width="'.$tsize[0].'" class="lazy" data-original="'.$h_thumb_link.'" src="'.$base.'/lib/static/grey.gif">'.
'<noscript><img id="thumb_'.$i_id.'" title="'.$h_tip.'" alt="'.$h_tip.'" height="'.$tsize[1].'" width="'.$tsize[0].'" src="'.$h_thumb_link.'"></noscript>'.
"</a></div></center>\n";
}
/**
* Put something in a rounded rectangle box; specific to the default theme
*/
@ -40,7 +11,6 @@ class Themelet extends BaseThemelet {
";
}
/**
* Add a generic paginator
*/
@ -67,7 +37,7 @@ class Themelet extends BaseThemelet {
private function build_paginator($current_page, $total_pages, $base_url, $query) {
$next = $current_page + 1;
$prev = $current_page - 1;
$rand = rand(1, $total_pages);
$rand = mt_rand(1, $total_pages);
$at_start = ($current_page <= 1 || $total_pages <= 1);
$at_end = ($current_page >= $total_pages);