From 3741acaec618fde1e4c230ee2a503987746235e4 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 30 Dec 2005 13:14:01 +0000 Subject: [PATCH] Branched from version 1.1. --- Changes | 9 ++ Memories.pm | 148 +++++++++++++++++++++ Memories/Album.pm | 77 +++++++++++ Memories/Comment.pm | 7 + Memories/Config.pm | 55 ++++++++ Memories/DBI.pm | 7 + Memories/Photo.pm | 239 ++++++++++++++++++++++++++++++++++ Memories/SystemTag.pm | 62 +++++++++ Memories/Tag.pm | 100 ++++++++++++++ Memories/User.pm | 67 ++++++++++ README | 59 +++++++++ memories.sql | 58 +++++++++ tag_dates | 10 ++ templates/album/denied | 7 + templates/album/list | 25 ++++ templates/album/view | 9 ++ templates/album_adder | 9 ++ templates/calendar | 43 ++++++ templates/custom/list | 20 +++ templates/footer | 9 ++ templates/frontpage | 35 +++++ templates/header | 23 ++++ templates/login_box | 34 +++++ templates/macros | 62 +++++++++ templates/memories.css | 8 ++ templates/memories.png | Bin 0 -> 40186 bytes templates/nav | 11 ++ templates/pager | 19 +++ templates/photo/comment | 18 +++ templates/photo/exif | 16 +++ templates/photo/recent | 18 +++ templates/photo/tagedit | 21 +++ templates/photo/upload | 63 +++++++++ templates/photo/view | 86 ++++++++++++ templates/picture/view | 7 + templates/recent.rss | 22 ++++ templates/rhs | 33 +++++ templates/static/1-s.gif | Bin 0 -> 646 bytes templates/static/1.gif | Bin 0 -> 649 bytes templates/static/2-s.gif | Bin 0 -> 718 bytes templates/static/2.gif | Bin 0 -> 694 bytes templates/static/3-s.gif | Bin 0 -> 718 bytes templates/static/3.gif | Bin 0 -> 695 bytes templates/static/4-s.gif | Bin 0 -> 680 bytes templates/static/4.gif | Bin 0 -> 668 bytes templates/static/5-s.gif | Bin 0 -> 710 bytes templates/static/5.gif | Bin 0 -> 692 bytes templates/static/6-s.gif | Bin 0 -> 719 bytes templates/static/6.gif | Bin 0 -> 708 bytes templates/static/7-s.gif | Bin 0 -> 673 bytes templates/static/7.gif | Bin 0 -> 672 bytes templates/static/8-s.gif | Bin 0 -> 731 bytes templates/static/8.gif | Bin 0 -> 713 bytes templates/static/9-s.gif | Bin 0 -> 731 bytes templates/static/9.gif | Bin 0 -> 704 bytes templates/static/memories.css | 141 ++++++++++++++++++++ templates/static/memories.png | Bin 0 -> 38516 bytes templates/static/upload.js | 82 ++++++++++++ templates/systemtag/list | 36 +++++ templates/systemtag/view | 14 ++ templates/tag/list | 36 +++++ templates/tag/list_js | 1 + templates/tag/view | 28 ++++ templates/tagcloud | 4 + templates/test | 2 + templates/user/album_list | 41 ++++++ templates/user/list | 25 ++++ templates/user/view | 7 + 68 files changed, 1913 insertions(+) create mode 100644 Changes create mode 100644 Memories.pm create mode 100644 Memories/Album.pm create mode 100644 Memories/Comment.pm create mode 100644 Memories/Config.pm create mode 100644 Memories/DBI.pm create mode 100644 Memories/Photo.pm create mode 100644 Memories/SystemTag.pm create mode 100644 Memories/Tag.pm create mode 100644 Memories/User.pm create mode 100644 README create mode 100644 memories.sql create mode 100644 tag_dates create mode 100644 templates/album/denied create mode 100644 templates/album/list create mode 100644 templates/album/view create mode 100644 templates/album_adder create mode 100644 templates/calendar create mode 100644 templates/custom/list create mode 100644 templates/footer create mode 100644 templates/frontpage create mode 100644 templates/header create mode 100644 templates/login_box create mode 100644 templates/macros create mode 100644 templates/memories.css create mode 100644 templates/memories.png create mode 100644 templates/nav create mode 100644 templates/pager create mode 100644 templates/photo/comment create mode 100644 templates/photo/exif create mode 100644 templates/photo/recent create mode 100644 templates/photo/tagedit create mode 100644 templates/photo/upload create mode 100644 templates/photo/view create mode 100644 templates/picture/view create mode 100644 templates/recent.rss create mode 100644 templates/rhs create mode 100644 templates/static/1-s.gif create mode 100644 templates/static/1.gif create mode 100644 templates/static/2-s.gif create mode 100644 templates/static/2.gif create mode 100644 templates/static/3-s.gif create mode 100644 templates/static/3.gif create mode 100644 templates/static/4-s.gif create mode 100644 templates/static/4.gif create mode 100644 templates/static/5-s.gif create mode 100644 templates/static/5.gif create mode 100644 templates/static/6-s.gif create mode 100644 templates/static/6.gif create mode 100644 templates/static/7-s.gif create mode 100644 templates/static/7.gif create mode 100644 templates/static/8-s.gif create mode 100644 templates/static/8.gif create mode 100644 templates/static/9-s.gif create mode 100644 templates/static/9.gif create mode 100644 templates/static/memories.css create mode 100644 templates/static/memories.png create mode 100644 templates/static/upload.js create mode 100644 templates/systemtag/list create mode 100644 templates/systemtag/view create mode 100644 templates/tag/list create mode 100644 templates/tag/list_js create mode 100644 templates/tag/view create mode 100644 templates/tagcloud create mode 100644 templates/test create mode 100644 templates/user/album_list create mode 100644 templates/user/list create mode 100644 templates/user/view diff --git a/Changes b/Changes new file mode 100644 index 0000000..de9c121 --- /dev/null +++ b/Changes @@ -0,0 +1,9 @@ +1.1 - Mon Oct 31 23:59:52 GMT 2005 + + - RSS feeds available from [%base%]/recent.rss + - Javascript suggestion of tags + - Calendaring and system tags + - Visual cleanups + - Concept of "enclosing tag" as well as "inside this tag" + - Minor fixes (zap cache on upload, URI escaping, etc.) + - Pager uses gifs diff --git a/Memories.pm b/Memories.pm new file mode 100644 index 0000000..33fbf40 --- /dev/null +++ b/Memories.pm @@ -0,0 +1,148 @@ +package Memories; +use strict; +use HTML::TagCloud; +use URI; +use Maypole::Application qw(Upload Authentication::UserSessionCookie +-Debug); +use Memories::Config; +use Memories::DBI; +use Memories::Photo; +use Memories::Comment; +use Memories::Tag; +use Memories::SystemTag; +use Memories::User; +use Memories::Album; +use URI::Escape; +use Calendar::Simple; + +Memories->config->auth->{ user_field } = "name"; +Memories->config->model("Maypole::Model::CDBI::Plain"); +Memories->setup([qw/ Memories::Photo Memories::User Memories::Tag +Memories::Album Memories::SystemTag/]); + +sub message { + my ($self, $message) = @_; + push @{$self->{template_args}{messages}}, $message; +} + +sub additional_data { + my $r = shift; + if ($r->params->{view_cal}) { + $r->{template_args}{view_cal} = eval { + Time::Piece->strptime($r->{params}{view_cal}, "%Y-%m-%d") }; + } + $r->{template_args}{now} = Time::Piece->new; +} + +use Maypole::Constants; +sub authenticate { + my ($self, $r) = @_; + return DECLINED if $self->path =~/static|store/; # XXX + $r->get_user; + return OK; +} + + +use Cache::SharedMemoryCache; +my %cache_options = ( 'namespace' => 'MemoriesStuff', + 'default_expires_in' => 600 ); +my $cache = + new Cache::SharedMemoryCache( \%cache_options ) or + croak( "Couldn't instantiate SharedMemoryCache" ); + +sub zap_cache { $cache->Clear } +use Storable qw(freeze); use MIME::Base64; +sub do_cached { + my ($self, $codeblock,$arg) = @_; + my $key = 0+$codeblock; if ($arg) { $key .=":".encode_base64(freeze(\$arg)); } + my $c = $cache->get(0+$codeblock); return @$c if $c; + my @stuff = $codeblock->($arg); + $cache->set(0+$codeblock, [ @stuff ]); + return @stuff; +} + +sub _recent_uploads { Memories::Photo->search_recent() } + +sub recent_uploads { shift->do_cached(\&_recent_uploads) } +sub tagcloud { shift->do_cached(\&_tagcloud) } + +sub _tagcloud { + my $cloud = HTML::TagCloud->new(); + my $base = Memories->config->uri_base."tag/view/"; + for my $tagging (Memories::Tagging->search_summary) { + my $name = $tagging->tag->name; + $cloud->add($name, + $base.uri_escape($name), + $tagging->{count} + ) + } + $cloud +} + +sub calendar { + # shift->do_cached(\&_calendar, shift ) } +#sub _calendar { + my $self = shift; + my $arg = shift; + my ($y, $m) = split /-/, ($arg || Time::Piece->new->ymd); + my @m = Calendar::Simple::calendar($m, $y); + my @month; + foreach my $week (@m) { + my @weekdays; + foreach my $day (@$week) { + my $d = { day => $day }; + if ($day) { + my $tag = "date:$y-$m-".sprintf("%02d", $day); + my ($x) = Memories::SystemTag->search(name => $tag); + if ($x) { $d->{tag} = "/system_tag/view/$tag" } + } + push(@weekdays, $d); + } + push(@month, \@weekdays); + } + return \@month; +} + +# THIS IS A HACK + +use Time::Seconds; +sub Time::Piece::next_month { + my $tp = shift; + my $month = $tp + ONE_MONTH; + return if $month > Time::Piece->new; + return $month +} +sub Time::Piece::prev_month { + my $tp = shift; + my $month = $tp - ONE_MONTH; + return $month +} + + +sub tag_select { + my ($r, $tags, $photos) = @_; + # XXX only affects current page + my %counter; + for (map {$_->tags} @$photos) { + $counter{$_->name}++; + } + delete $counter{$_->name} for @$tags; + my @super; + + my $cloud = HTML::TagCloud->new(); + my $base = $r->config->uri_base.$r->path."/"; + my $tags; + for my $name (sort {$a cmp $b} keys %counter) { + if ($counter{$name} == @$photos) { + push @super, $name; + } else { + $cloud->add($name, $base.uri_escape($name), $counter{$name}); + $tags++; + } + } + my %res; + if (@super) { $res{super} = \@super } + if ($tags) { $res{cloud} = $cloud } + \%res; +} +1; diff --git a/Memories/Album.pm b/Memories/Album.pm new file mode 100644 index 0000000..b4f869d --- /dev/null +++ b/Memories/Album.pm @@ -0,0 +1,77 @@ +package Memories::Album; +use base qw(Memories::DBI Maypole::Model::CDBI::Plain); +__PACKAGE__->columns(Essential => qw/id name user privacy/); +Memories::Album->has_a(user => "Memories::User"); +Memories::User->has_many(albums => "Memories::Album"); + +sub view :Exported { + my ($self, $r) = @_; + my $album = $r->objects->[0]; + if ($album->privacy && $album->user != $r->user) { + $r->template("denied"); return; + } + $r->template_args->{photos} = [ $album->photos ]; +} + +sub list :Exported { + my ($self, $r) = @_; + my $page = $r->{params}{page} || 1; + my $pager = Memories::Album->pager( + Memories->config->{photos_per_page}, $page); + $r->{objects} = [$pager->search(privacy => 0)]; + $r->{template_args}{pager} = $pager; +} + +sub edit :Exported { + my ($self, $r) = @_; + use Data::Dumper; warn Dumper($r->{params}); + my $album; + if ($r->{params}{album}) { # We're adding to an album + $album = $self->retrieve($r->{params}{album}); + if (!$album or $album->user != $r->user) { + $r->template("denied"); return; + } + for (map /(\d+)/,grep /add\d+/, keys %{$r->{params}}) { + Memories::AlbumEntry->create({ + album => $album->id, + photo => $_ + }); + } + } else { + $album = $r->{objects}[0]; + if (!$album or $album->user != $r->user) { + $r->template("denied"); return; + } + for (map /(\d+)/,grep /delete\d+/, keys %{$r->{params}}) { + my ($ae) = Memories::AlbumEntry->search({ + album => $album->id, + photo => $_ + }); + $ae->delete if $ae; + } + } + $r->objects([ $album ]); + $r->template("view"); $self->view($r); +} + +package Memories::AlbumEntry; +use base qw(Memories::DBI); +__PACKAGE__->table("album_entry"); +__PACKAGE__->columns(TEMP => qw/count/); +__PACKAGE__->columns(Essential => qw/id album photo/); +__PACKAGE__->set_sql(summary => qq/ +SELECT id, album, count(*) AS count +FROM album_entry; +GROUP BY album +ORDER BY count DESC +LIMIT 50 + /); +Memories::AlbumEntry->has_a("photo" => "Memories::Photo"); +Memories::AlbumEntry->has_a("album" => "Memories::Album"); + +Memories::Photo->has_many(albums => ["Memories::AlbumEntry" => "album"]); +Memories::Photo->has_many(albumentries => "Memories::AlbumEntry"); +Memories::Album->has_many(photos => ["Memories::AlbumEntry" => "photo"] ); +Memories::Album->has_many(albumentries => "Memories::AlbumEntry"); + +1; diff --git a/Memories/Comment.pm b/Memories/Comment.pm new file mode 100644 index 0000000..2b7f0ca --- /dev/null +++ b/Memories/Comment.pm @@ -0,0 +1,7 @@ +package Memories::Comment; +use base qw(Memories::DBI); +__PACKAGE__->columns(Essential => qw/id name photo/); +__PACKAGE__->columns(Others => qw/content/); +Memories::Comment->has_a("photo" => "Memories::Photo"); + +1; diff --git a/Memories/Config.pm b/Memories/Config.pm new file mode 100644 index 0000000..f874eff --- /dev/null +++ b/Memories/Config.pm @@ -0,0 +1,55 @@ +package Memories::Config; +# PATHS AND URLS + +# This parameter should be the external address of your Memories +# installation +Memories->config->uri_base("http://memories.simon-cozens.org/"); + +# This is where your templates will live. +Memories->config->{template_root} = "/home/simon/maypole-sites/memories/templates"; + +# Here is where uploaded photos will be stored. Your web server user +# should own this directory. +Memories->config->{data_store} = "/web/photostore/"; + +# You also need to configure your web server so that it serves files out +# of the data store; this URL should be where that data store directory +# is exposed on the web. +Memories->config->{data_store_external} = "http://memories.simon-cozens.org/store/"; + +# Your database server: the first part should always be "dbi"; the +# second, the name of the DBD driver you're using (usually mysql unless +# you want to do your own thing); the final part, the name of the +# database. +# +# Initialize this database from memories.sql and give www-data (or +# equivalent) read/write access to all tables. +Memories->config->{dsn} = "dbi:mysql:memories"; + +# SESSION MANAGEMENT +# +# The name of any cookies this application should give out +Memories->config->{auth}{cookie_name} = "memories"; + +# Session file storage. Create these directories and have them owned by +# www-data +Memories->config->{auth}{session_args} = { + Directory => "/var/lib/memories/sessions", + LockDirectory => "/var/lib/memories/sessionlock", + }; + +# DISPLAY PARAMETERS +# +# It's OK to leave these as they are. +# +# The size of thumbnails to generate +Memories->config->{thumb_size} = "90x90"; + +# Sizes you want to scale to. "full" is special. +Memories->config->{sizes} = + [ qw/ 150x100 300x200 640x480 800x600 1024x768 1280x1024 full /]; + +# Number of photos on a page. It's best if this is a multiple of three +Memories->config->{photos_per_page} = 21; + +1; diff --git a/Memories/DBI.pm b/Memories/DBI.pm new file mode 100644 index 0000000..4d3595d --- /dev/null +++ b/Memories/DBI.pm @@ -0,0 +1,7 @@ +package Memories::DBI; +use base qw(Class::DBI::mysql); +Memories::DBI->connection(Memories->config->{dsn}); +Memories::DBI->autoupdate(1); +use Carp qw(carp); + +1; diff --git a/Memories/Photo.pm b/Memories/Photo.pm new file mode 100644 index 0000000..288ac4a --- /dev/null +++ b/Memories/Photo.pm @@ -0,0 +1,239 @@ +package Memories::Photo; +use strict; +use Carp qw(cluck confess); +use base qw(Memories::DBI Maypole::Model::CDBI::Plain); +use Time::Piece; +use constant PAGER_SYNTAX => "LimitXY"; +__PACKAGE__->columns(Essential => qw(id title uploader uploaded x y)); +__PACKAGE__->columns(TEMP => qw/exif_object/); +__PACKAGE__->set_sql(recent => q{ +SELECT __ESSENTIAL__ +FROM __TABLE__ +ORDER BY uploaded DESC +LIMIT 4 +}); + +__PACKAGE__->has_many(comments => "Memories::Comment"); +__PACKAGE__->has_a(uploader => "Memories::User"); +__PACKAGE__->has_a(uploaded => "Time::Piece", + inflate => sub { Time::Piece->strptime(shift, "%Y-%m-%d %H:%M:%S") }, + deflate => 'datetime', +); + +sub do_upload :Exported { + my ($self, $r) = @_; + my %upload = $r->upload("photo"); + + # XXX Stop anonymous uploads! + my $photo = $self->create({ + uploader => $r->user, + uploaded => Time::Piece->new(), + title => ($r->params->{title} || $upload{filename}) + }); + + # Dump content + if (!open OUT, ">". $photo->path("file")) { + die "Can't write ".$photo->path("file")." because $!"; + } + # XXX Check it's a JPEG, etc. + # XXX Unzip ZIP file + print OUT $upload{content}; + close OUT; + my ($x, $y) = dim(image_info($photo->path)); + $photo->x($x); $photo->y($y); + + # Rotate? + $photo->unrotate(); + + $photo->make_thumb; + $photo->add_tags($r->{params}{tags}); + Memories->zap_cache(); + + # Add system tags here + my $tag = "date:".$photo->shot->ymd; + $photo->add_to_system_tags({tag => Memories::SystemTag->find_or_create({name =>$tag}) }); + + # Set it up to go again + $r->objects([$photo]); + $r->template("view"); + $r->message("Thanks for the upload! ". + ($r->{params}{tags} ? "" + : "Don't forget to config->uri_base."photo/view/".$photo->id."?active=tagedit\">tag your photo" + ) + ); +} + +sub upload :Exported {} + +use Class::DBI::Plugin::Pager; +use Class::DBI::Plugin::AbstractCount; + +sub recent :Exported { + my ($self, $r) = @_; + my $page = $r->params->{page} || 1; + my $pager = $self->pager( + per_page => Memories->config->{photos_per_page}, + page => $page, + syntax => PAGER_SYNTAX, + order_by => "uploaded desc" + ); + $r->objects([$pager->retrieve_all ]); + $r->{template_args}{pager} = $pager; +} + +sub add_comment :Exported { + my ($self, $r, $photo) = @_; + $r->template("view"); + $r->objects->[0]->add_to_comments({ + name => $r->params->{name}, + content => $r->params->{content} + }); +} + +sub format { + "jpg" # For now +} + +use Cache::MemoryCache; +use Image::Info qw(dim image_info); +use Image::ExifTool; +my $cache = new Cache::MemoryCache( { 'namespace' => 'MemoriesInfo' }); + +sub unrotate { + my $self = shift; + my $orient = $self->exif_info->{EXIF}->{Orientation}; + return if $orient !~/Rotate (\d+)/i; + my $steps = $1/90; + my $img = Image::Imlib2->load($self->path("file")); + $img->image_orientate($steps); + $img->save($self->path("file")); +} + +sub exif_info { + my $self = shift; + my $info = $self->exif_object; + return $info if $info; + # Get it from the Cache + if (!($info = $cache->get($self->id))) { + # Create it + $info = $self->_exif_info; + $cache->set($self->id, $info); + } + $self->exif_object($info); + $info; +} + +sub _exif_info { + my $exifTool = new Image::ExifTool; + $exifTool->Options(Group0 => ['EXIF', 'MakerNotes', 'Composite']); + my $info = $exifTool->ImageInfo(shift->path); + my $hash = {}; + foreach my $tag ($exifTool->GetFoundTags('Group0')) { + my $group = $exifTool->GetGroup($tag); + my $val = $info->{$tag}; + next if ref $val eq 'SCALAR'; + next if $val =~ /^[0\s]*$/; + $hash->{$group}->{$exifTool->GetDescription($tag)} = $val; + } + return $hash; +} + +# XXX Cache this +sub dimensions { join "x", $_[0]->x, $_[0]->y } + +sub is_bigger { + my ($self, $size) = @_; + return 1 if $size eq "full"; + my ($w, $h) = ($self->x, $self->y); + my ($w2, $h2) = split /x/, $size; + return 1 if $w > $w2 or $h > $h2; + return 0; +} + +sub sized_url { # Use this rather than ->path from TT + my ($self, $size) = @_; + my $url = Memories->config->{data_store_external}; + my $resized = Memories->config->{sizes}->[$size]; + if (!$resized) { cluck "Asked for crazy size $size"; return; } + if ($resized eq "full") { return $self->path("url") } + $self->scale($resized) + unless -e $self->path( file => $resized ); + return $self->path(url => $resized); +} + +sub path { + my ($self, $is_url, $scale) = @_; + my $path = + Memories->config->{$is_url eq "url" ? "data_store_external" : "data_store" }; + if ($scale) { $path .= "$scale/" } + # Make dir if it doesn't exist, save trouble later + use File::Path; + if ($is_url ne "url") {mkpath($path);} + $path .= $self->id.".".$self->format; + return $path; +} + +sub thumb_url { shift->path(url => Memories->config->{thumb_size}); } +sub make_thumb { shift->scale(Memories->config->{thumb_size}, 1); } + +use Image::Imlib2; +sub scale { + my ($self, $scale, $swap) = @_; + my ($x, $y) = split /x/, $scale; + # Find out smaller axis + my ($cur_x, $cur_y) = ($self->x, $self->y); + if (!$swap) { + if ($cur_x < $cur_y) { $y = 0 } else { $x = 0 } + } else { + if ($cur_x > $cur_y) { $y = 0 } else { $x = 0 } + } + my $img = Image::Imlib2->load($self->path("file")); + unless ($img) { + cluck "Couldn't open image file ".$self->path("file"); + return; + } + $img = $img->create_scaled_image($x, $y); + $img->image_set_format("jpeg"); + my $file = $self->path( file => $scale ); + $img->save($file); + if ($!) { + cluck "Couldn't write image file $file ($!)"; + return; + } +} + +use Text::Balanced qw(extract_multiple extract_quotelike); +sub edit_tags :Exported { + my ($self, $r) = @_; + my $photo = $r->objects->[0]; + my %params = %{$r->params}; + for (keys %params) { + next unless /delete_(\d+)/; + my $tagging = Memories::Tagging->retrieve($1) or next; + next unless $tagging->photo->id == $photo->id; + $tagging->delete; + } + $photo->add_tags($params{newtags}); + $r->template("view"); +} + +sub add_tags { + my ($photo, $tagstring) = @_; + + for my $tag (map { s/^"|"$//g; $_} extract_multiple(lc $tagstring, [ \&extract_quotelike, qr/([^\s]+)/ ], undef,1)) { + $photo->add_to_tags({tag => Memories::Tag->find_or_create({name =>$tag}) }) + } +} + +sub shot { + my $self = shift; + my $exif = $self->exif_info->{EXIF}; + my ($dt) = + grep {$_ and /[^ 0:]/} + ($exif->{ 'Shooting Date/Time' }, + $exif->{ 'Date/Time Of Digitization' }, + $exif->{ 'Date/Time Of Last Modification' }); + if (!$dt) { return $self->uploaded } + return Time::Piece->strptime($dt, "%Y:%m:%d %T") || $self->uploaded; +} +1; diff --git a/Memories/SystemTag.pm b/Memories/SystemTag.pm new file mode 100644 index 0000000..d4f8439 --- /dev/null +++ b/Memories/SystemTag.pm @@ -0,0 +1,62 @@ +package Memories::SystemTag; +use strict; +use base qw(Memories::DBI Maypole::Model::CDBI::Plain); +__PACKAGE__->columns(Essential => qw/id name/); +__PACKAGE__->table("system_tag"); + +Memories::Photo->set_sql(sorted_by_system_tag => q/ +SELECT photo.id as id, title, uploader, uploaded, x, y +FROM photo, system_tag, system_tagging +WHERE system_tagging.photo = photo.id + AND system_tagging.tag = system_tag.id + AND system_tag.id = ? +ORDER BY photo.uploaded DESC +/ +); +sub view :Exported { + my ($self, $r) = @_; + my $tag; + my $page = $r->params->{page} || 1; + my $pager = Class::DBI::Pager::_pager("Memories::Photo", + Memories->config->{photos_per_page}, $page); + $r->{template_args}{pager} = $pager; + + if (!$r->objects) { + $tag = $self->search(name => $r->{args}->[0])->first; + } else { + $tag = $r->objects->[0]; # Should hardly happen + } + $r->{template_args}{tag} = $tag; + $r->{template_args}{tags} = [$tag]; # For selector + $r->{template_args}{photos} = + [$pager->search_sorted_by_system_tag($tag->id)]; +} + +package Memories::SystemTagging; +use base qw(Memories::DBI); +use Class::DBI::Pager; +__PACKAGE__->table("system_tagging"); +__PACKAGE__->columns(TEMP => qw/count/); +__PACKAGE__->columns(Essential => qw/id tag photo/); +__PACKAGE__->set_sql(summary => qq/ +SELECT id, system_tag, count(*) AS count +FROM system_tagging +GROUP BY system_tag +ORDER BY count DESC +LIMIT 50 + /); +__PACKAGE__->set_sql(all => qq/ +SELECT id, tag, count(*) AS count +FROM system_tagging +GROUP BY system_tag +ORDER BY count DESC + /); +Memories::SystemTagging->has_a("photo" => "Memories::Photo"); +Memories::SystemTagging->has_a("tag" => "Memories::SystemTag"); + +Memories::Photo->has_many(system_tags => ["Memories::SystemTagging" => "system_tag"]); +Memories::Photo->has_many(system_taggings => "Memories::SystemTagging"); +Memories::SystemTag->has_many(photos => ["Memories::SystemTagging" => "photo"] ); +Memories::SystemTag->has_many(system_taggings => "Memories::SystemTagging"); + +1; diff --git a/Memories/Tag.pm b/Memories/Tag.pm new file mode 100644 index 0000000..bcaa6c0 --- /dev/null +++ b/Memories/Tag.pm @@ -0,0 +1,100 @@ +package Memories::Tag; +use strict; +use base qw(Memories::DBI Maypole::Model::CDBI::Plain); +__PACKAGE__->columns(Essential => qw/id name/); + +Memories::Photo->set_sql(sorted_by_tag => q/ +SELECT photo.id as id, title, uploader, uploaded, x, y +FROM photo, tag, tagging +WHERE tagging.photo = photo.id + AND tagging.tag = tag.id + AND tag.id = ? +ORDER BY photo.uploaded DESC +/ +); + +sub view :Exported { + my ($self, $r) = @_; + my $tag; + my $page = $r->params->{page} || 1; + my $pager = Class::DBI::Pager::_pager("Memories::Photo", + Memories->config->{photos_per_page}, $page); + $r->{template_args}{pager} = $pager; + + if (@{$r->args} > 1) { # This is actually an n-level search + $self->multi_search($r); + } else { + if (!$r->objects) { + $tag = $self->search(name => $r->{args}->[0])->first; + } else { + $tag = $r->objects->[0]; # Should hardly happen + } + $r->{template_args}{tag} = $tag; + $r->{template_args}{tags} = [$tag]; # For selector + $r->{template_args}{photos} = + [$pager->search_sorted_by_tag($tag->id)]; + } +} + +sub multi_search { + my ($self, $r) = @_; + my $counter = "tagaaa"; + my @tags; + for (@{$r->{args}}) { + my $tag = $self->search(name => $_)->first; + if (!$tag) { return } + push @tags, { tag => $tag, id => $tag-> id, counter => $counter++ }; + } + my $sql = "select photo.id as id, photo.title as title, uploader, uploaded, x, y +from photo, ". (join ",", map{ "tagging ".$_->{counter} } @tags). +" where ". (join " AND ", map { "$_->{counter}.tag=$_->{id} and photo.id = $_->{counter}.photo" } @tags); + +$sql .= " order by photo.uploaded desc"; + my $sth = $self->db_Main->prepare($sql); + $r->{template_args}{photos} = [ $r->{template_args}{pager}->sth_to_objects($sth) ]; + $sth->finish; + $r->{template_args}{tags} = [ map { $_->{tag} } @tags ]; +} + +sub list :Exported { + my ($self, $r) = @_; + my $page = $r->params->{page} || 1; + my $pager = Memories::Tagging->pager( + Memories->config->{photos_per_page}, $page + ); + $r->{template_args}{pager} = $pager; + $r->objects([map {$_->tag} $pager->search_all]); +} + +sub list_js :Exported { + my ($self, $r) = @_; + $r->objects([ $self->retrieve_all ]); +} + +package Memories::Tagging; +use base qw(Memories::DBI); +use Class::DBI::Pager; +__PACKAGE__->columns(TEMP => qw/count/); +__PACKAGE__->columns(Essential => qw/id tag photo/); +__PACKAGE__->set_sql(summary => qq/ +SELECT id, tag, count(*) AS count +FROM tagging +GROUP BY tag +ORDER BY count DESC +LIMIT 50 + /); +__PACKAGE__->set_sql(all => qq/ +SELECT id, tag, count(*) AS count +FROM tagging +GROUP BY tag +ORDER BY count DESC + /); +Memories::Tagging->has_a("photo" => "Memories::Photo"); +Memories::Tagging->has_a("tag" => "Memories::Tag"); + +Memories::Photo->has_many(tags => ["Memories::Tagging" => "tag"]); +Memories::Photo->has_many(taggings => "Memories::Tagging"); +Memories::Tag->has_many(photos => ["Memories::Tagging" => "photo"] ); +Memories::Tag->has_many(taggings => "Memories::Tagging"); + +1; diff --git a/Memories/User.pm b/Memories/User.pm new file mode 100644 index 0000000..2fa82ca --- /dev/null +++ b/Memories/User.pm @@ -0,0 +1,67 @@ +package Memories::User; +use base qw(Memories::DBI Maypole::Model::CDBI::Plain); +__PACKAGE__->columns(All => qw/id name password/); +__PACKAGE__->has_many(photos => "Memories::Photo"); + +sub register :Exported { + my ($class, $r) = @_; + my $login = $r->params->{name}; + my $pass = $r->params->{password}; + $r->template("frontpage"); + return if $r->user; + + # Do we already exist? + if (!$login) { $r->template("login"); $r->message("You didn't enter a user name"); return; } + my ($user) = $class->search(name => $login); + if ($user) { $r->template("login"); $r->message("User name already exists"); return; } + $user = $class->create({name => $login, password => $pass }); + $r->user($user, 0); + $r->login_user($user->id); + +} + +sub view :Exported { + my ($self, $r) = @_; + my $user = $r->objects->[0]; + my $page = $r->params->{page} || 1; + my $pager = Class::DBI::Pager::_pager("Memories::Photo", + Memories->config->{photos_per_page}, $page); + $r->{template_args}{photos} = [$pager->search(uploader => + $user->id,{order_by => "uploaded desc"}) ]; + $r->{template_args}{pager} = $pager; + $r->{template_args}{albums} = [$user->albums(privacy => 0)]; +} + +# Album support! + +sub edit_albums :Exported { + my ($self, $r) = @_; + $r->{template} = "view"; + $self->view($r); + my $user = $r->objects->[0]; + return unless $r->user and $r->user->id == $user->id; + if ($r->{params}{create}) { + $user->add_to_albums({ + privacy => !!($r->{params}{new_privacy}), + name => $r->{params}{new_name} + }); + } elsif ($r->{params}{changes}) { + for my $album ($user->albums) { #XXX + warn "Setting $album privacy to ". + $r->{params}{"privacy_".$album->id}; + $album->privacy(!!$r->{params}{"privacy_".$album->id}); + } + } else { + my @to_delete = map /(\d+)/, + grep /delete_\d+/, keys %{$r->{params}}; + for (@to_delete) { + my $album = Memories::Album->retrieve($_); + if ($album and $album->user->id == $user->id) { + $album->delete + } + } + } + +} + +1; diff --git a/README b/README new file mode 100644 index 0000000..abc3838 --- /dev/null +++ b/README @@ -0,0 +1,59 @@ +Updating from an earlier release? Read the bit at the bottom! + +Installing the Memories photo sharing application +------------------------------------------------- + +First, Perl modules. This is the hard part. You will need: + Maypole (good luck) + Class::DBI + DBI + DBD::mysql + Class::DBI::mysql + Image::Info + Image::Imlib2 (requires libimlib2 and libimlib2-dev packages) + Time::Piece + Cache::Cache + Maypole::Plugin::Upload + Maypole::Plugin::Authentication::UserSessionCookie + HTML::TagCloud + +Apache mod_perl is recommended. Memories can also be run as a CGI +application, but you're on your own. + +You will also need a MySQL database. Again, in theory other databases +can be used, but in practice, you're on your own again. + +Configure Maypole/Config.pm to your site, and follow the instructions in +there - it will require you to set other things up as well. + +Test that everything works: + + perl -MMemories -e1 + +If this produces no errors, you're good to configure Apache. I have +Memories living in "/home/simon/maypole-sites/memories", and my photo +storage in "/opt/store/", and so my configuration looks like this: + + + use lib qw( /home/simon/maypole-sites/memories/ ); + + + PerlModule Memories + Alias /memories/static/ /home/simon/maypole-sites/memories/templates/static/ + Alias /memories/store/ /opt/store/ + + + PerlHandler Memories + SetHandler perl-script + + +Restart Apache, register yourself and get uploading! + + +Updating Memories 1.0 to 1.1 +---------------------------- + +1) Create the system_tags and system_taggings table as in memories.sql + +2) Run the tag_dates script. + diff --git a/memories.sql b/memories.sql new file mode 100644 index 0000000..9ebe256 --- /dev/null +++ b/memories.sql @@ -0,0 +1,58 @@ +CREATE TABLE photo ( + id integer not null auto_increment primary key, + title varchar(255), + uploader integer, + uploaded datetime, + x integer, + y integer +); + +CREATE TABLE comment ( + id integer not null auto_increment primary key, + name varchar(255), + content text, + photo integer +); + +CREATE TABLE user ( + id integer not null auto_increment primary key, + name varchar(255), + password varchar(255) +); + +CREATE TABLE tag ( + id integer not null auto_increment primary key, + name varchar(255) +); + +CREATE TABLE tagging ( + id integer not null auto_increment primary key, + tag integer, + photo integer +); + +CREATE TABLE album ( + id integer not null auto_increment primary key, + name varchar(255), + user integer, + privacy integer +); + +CREATE TABLE album_entry ( + id integer not null auto_increment primary key, + album integer, + photo integer +); + +CREATE TABLE system_tag ( + id integer not null auto_increment primary key, + name varchar(255) +); + +CREATE TABLE system_tagging ( + id integer not null auto_increment primary key, + tag integer, + photo integer +); + + diff --git a/tag_dates b/tag_dates new file mode 100644 index 0000000..e44af81 --- /dev/null +++ b/tag_dates @@ -0,0 +1,10 @@ +use Memories; +my $it = Memories::Photo->retrieve_all; + +my $thing = $it->first; +do { + print $thing->title, " $tag\n"; + my $tag = "date:".$thing->shot->ymd; + $thing->add_to_system_tags({tag => Memories::SystemTag->find_or_create({name + =>$tag}) }); +} while $thing = $it->next; diff --git a/templates/album/denied b/templates/album/denied new file mode 100644 index 0000000..7b641a9 --- /dev/null +++ b/templates/album/denied @@ -0,0 +1,7 @@ +[% INCLUDE header %] +
+This album has been marked private, and you do not have permission to +view it. +
+ +[% INCLUDE footer; %] diff --git a/templates/album/list b/templates/album/list new file mode 100644 index 0000000..0229289 --- /dev/null +++ b/templates/album/list @@ -0,0 +1,25 @@ +[% INCLUDE header %] +[% PROCESS macros %] + + +[% WHILE objects.size > 0 %] + + [% SET minilist = objects.splice(0,3) %] + [% FOR album = minilist %] + + [% END %] + +[% END %] +
+ [% album %]
+

+ + [%album.photos.size %] + photo[%-"s" IF album.photos.size != 1 %] +
+ [%album.user%] +
+
+[% INCLUDE pager %] +[% INCLUDE footer %] diff --git a/templates/album/view b/templates/album/view new file mode 100644 index 0000000..a8ad02d --- /dev/null +++ b/templates/album/view @@ -0,0 +1,9 @@ +[% INCLUDE header %] +[% PROCESS macros %] +

[% album.name %]

+[% IF album.user == request.user %] + [% view_page_of(photos, "delete") %] +[% ELSE %] +[% view_page_of(photos) %] +[% END %] +[% INCLUDE footer %] diff --git a/templates/album_adder b/templates/album_adder new file mode 100644 index 0000000..2c3db73 --- /dev/null +++ b/templates/album_adder @@ -0,0 +1,9 @@ +[% IF request.user.albums.size > 0 %] + Add to: + + +[% END %] diff --git a/templates/calendar b/templates/calendar new file mode 100644 index 0000000..700072f --- /dev/null +++ b/templates/calendar @@ -0,0 +1,43 @@ +
+[% IF request.action == "view" %] + [% SET shot = photo.shot %] +[% END %] +[% SET date = view_cal || shot || now %] +[% SET imp_date = shot || now %] +[% SET next = date.next_month %] +[% SET prev = date.prev_month %] +[% SET calendar = request.calendar(date.ymd) %] + + + + + + + + + +[% FOR week = calendar %] + + +[% FOR day = week %] + [% IF day.tag %] + [% IF shot AND day.day == imp_date.mday %] + + [% ELSE %] + + [% END %] +[% END %] + +[% END %] +
« + [% date.strftime("%Y-%m") %] + [% IF next %] + » + [% END %] +
S M + TWTFS
+ [% ELSE %] + + [% END %] + [% day.day %] [% day.day %]
+
diff --git a/templates/custom/list b/templates/custom/list new file mode 100644 index 0000000..3dd50b3 --- /dev/null +++ b/templates/custom/list @@ -0,0 +1,20 @@ +[% INCLUDE header %] +[% PROCESS macros %] + + +[% WHILE objects.size > 0 %] + + [% SET minilist = objects.splice(0,3) %] + [% FOR object = minilist %] + + [% END %] + +[% END %] +
+ [% object %]
+

+ + [%object.photos.size %] + photo[%-"s" IF object.photos.size != 1 %] +
+[% INCLUDE footer %] diff --git a/templates/footer b/templates/footer new file mode 100644 index 0000000..64186ac --- /dev/null +++ b/templates/footer @@ -0,0 +1,9 @@ + + + + [% INCLUDE rhs %] + + + + + diff --git a/templates/frontpage b/templates/frontpage new file mode 100644 index 0000000..2b36f1e --- /dev/null +++ b/templates/frontpage @@ -0,0 +1,35 @@ +[% INCLUDE header %] +

Welcome to Memories

+ +

+ Memories is a site where you can upload and share your photos of + college life with your friends. +

+

+ To view other people's photos, look at the user list or the album list. +

+

+ Alternatively, Memories supports tagging photos with names, places, or + other descriptive terms. Browse based on the tags on the right, or look + at the full tag list. +

+
+[% IF request.user %] +

+Now that you're logged in, you can start uploading photos. Create some albums or +check out what you've uploaded at your home page. +

+[% ELSE %] +

+To get started uploading your own photos, you'll need to log in. If you +don't have an account, just go to the log in page anyway, choose a +username and password, and click "Register". So long as nobody else has that name, +we'll create an account for you immediately. +

+[% END %] +[% INCLUDE footer %] diff --git a/templates/header b/templates/header new file mode 100644 index 0000000..8dc15a6 --- /dev/null +++ b/templates/header @@ -0,0 +1,23 @@ + + + Memories - ANCC Photo Sharing + +[% IF request.params.active == "tagedit" %] + + + + +[% ELSE %] + + +[% END %] +[% INCLUDE nav %] + + +
+ [% IF messages %] +
+
    [% FOR m = messages %]
  • [%m%]
  • [% END %] +
+ [% END %] +
diff --git a/templates/login_box b/templates/login_box new file mode 100644 index 0000000..b875129 --- /dev/null +++ b/templates/login_box @@ -0,0 +1,34 @@ + [% INCLUDE header %] + +
+ [% IF request.user %] + Welcome, [% request.user.name %] + [% ELSE %] + + [% IF login_error %] +
[% login_error %]
+ [% END %] +
+
+ Login or register as a new user + + + + +
+ Username: + + +
+ Password: + + +
+ + +
+
+ [% END %] +
+ + [% INCLUDE footer %] diff --git a/templates/macros b/templates/macros new file mode 100644 index 0000000..f97cdd3 --- /dev/null +++ b/templates/macros @@ -0,0 +1,62 @@ +[% MACRO thumb(photo, album) BLOCK %] + + + + + [% IF request.user %] + [% IF album == 1 %] + + [% ELSIF album == 2 %] + + [% END %] + [% END %] +
+ + [%photo.title|html%] + +
+ + [% photo.title |html%] + + +
Uploaded by + + [% photo.uploader.name |html%] +
at [% photo.uploaded %]
Add to album:
Delete from album:
+[% END %] + +[% MACRO view_page_of(photos) BLOCK; %] +[% IF request.table == "album" AND request.template == "view" %] +[% SET editing_album = 1%] +[% END %] +[% IF editing_album %] +
+[% ELSE %] + +[% END %] +[% IF !photos OR ! photos.size %] +
+ This [% request.table %] is empty! +
+[% ELSE %] + +[% WHILE photos.size > 0 %] +[% SET triple = photos.splice(0,3) %] + + [% FOR photo = triple %] + + [% END %] + +[% END %] +
+ [% IF editing_album; thumb(photo, 2); ELSE; thumb(photo, 1); END %] +
+[% END %] +[% IF editing_album %] + +[% ELSE %] +[% INCLUDE album_adder %] +[% END %] +[% INCLUDE pager %] +
+[% END %] diff --git a/templates/memories.css b/templates/memories.css new file mode 100644 index 0000000..ac5608e --- /dev/null +++ b/templates/memories.css @@ -0,0 +1,8 @@ +body { background: #afa; } + +.recentuploads { + float:right; + background: #ddd; + padding: 10px; + border: 1px solid black; +} diff --git a/templates/memories.png b/templates/memories.png new file mode 100644 index 0000000000000000000000000000000000000000..c602c08d01c3a33f7b67a03544c0b3ffffb605cd GIT binary patch literal 40186 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�c24G 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 b$DzRps3;JAe8i=N@$jfCYl3POEhGN}Hvcn< literal 0 HcmV?d00001 diff --git a/templates/nav b/templates/nav new file mode 100644 index 0000000..f42bb06 --- /dev/null +++ b/templates/nav @@ -0,0 +1,11 @@ + diff --git a/templates/pager b/templates/pager new file mode 100644 index 0000000..8ff1ed0 --- /dev/null +++ b/templates/pager @@ -0,0 +1,19 @@ +[% IF pager.last_page > 1 %] + [% FOREACH num = [pager.first_page .. pager.last_page] %] + [% IF num == pager.current_page %] + [% IF num < 10 %] + + [% ELSE %] + [[% num %]] + [% END %] + [% ELSE %] + + [% IF num < 10 %] + + [% ELSE %] + [[% num %]] + [% END %] + + [% END %] +[% END %] +[% END %] diff --git a/templates/photo/comment b/templates/photo/comment new file mode 100644 index 0000000..498e5b6 --- /dev/null +++ b/templates/photo/comment @@ -0,0 +1,18 @@ +
+[% FOR comment = photo.comments %] +
+ [% comment.name | html %] writes...
+ [% comment.content %] +
+[% END %] +
+
+ Name:
+ +

+ +

+
+
+
diff --git a/templates/photo/exif b/templates/photo/exif new file mode 100644 index 0000000..b60ddbc --- /dev/null +++ b/templates/photo/exif @@ -0,0 +1,16 @@ +[% SET exif = photo.exif_info %] +[% FOR group = exif.keys %] + [% SET counter = 0 %] +

[% group %]

+ + [% FOR key = exif.$group.keys %] + + [% IF counter % 2 == 0 %] [% END %] + + + [% IF counter % 2 == 1 %] + [% ELSE %] [% END %] + [% SET counter = counter + 1 %] + [% END %] +
[% key %] [% exif.$group.$key %]
 
+[% END %] diff --git a/templates/photo/recent b/templates/photo/recent new file mode 100644 index 0000000..37d1ae3 --- /dev/null +++ b/templates/photo/recent @@ -0,0 +1,18 @@ +[% INCLUDE header %] +[% PROCESS macros %] +

Recent photos

+ +[% WHILE photos.size > 0 %] +[% SET triple = photos.splice(0,3) %] + + [% FOR photo = triple %] + + [% END %] + +[% END %] +
+ [% thumb(photo, 1) %] +
+ +[% INCLUDE pager %] +[% INCLUDE footer %] diff --git a/templates/photo/tagedit b/templates/photo/tagedit new file mode 100644 index 0000000..a34d8bd --- /dev/null +++ b/templates/photo/tagedit @@ -0,0 +1,21 @@ +
+Tagging advice: Tags should be words, (portrait, henry) or +phrases surrounded by double quotes. ("tall buildings") You can +put any number of tags in the "add tags" box, like this: +

+ landscape cambridge "tall buildings" +

+
+

Suggested tags

+
+
+ +Delete tags:
+
    +[% FOR tagging = photo.taggings %] +
  • [% tagging.tag %] +[% END %] +
+

Add tags:

+
diff --git a/templates/photo/upload b/templates/photo/upload new file mode 100644 index 0000000..d17d3cb --- /dev/null +++ b/templates/photo/upload @@ -0,0 +1,63 @@ + + + Memories - ANCC Photo Sharing + + + + + +[% INCLUDE nav %] + + +
+ [% IF messages %] +
+
    [% FOR m = messages %]
  • [%m%]
  • [% END %] +
+ [% END %] +
+

Upload a photo

+

+This is where you can upload your photographs. At the moment, you must +upload them one at a time; in the near future, you will be able to +upload a Zip file containing several photos. +

+

+Please note that it may take a while to transfer your photograph to the +server, so don't press stop or reload after pressing the Upload button. +

+ +
+ + + + + + + + + + + + +
Title:
Tags:
  +
+Tagging advice: Tags should be words, (portrait, henry) or +phrases surrounded by double quotes. ("tall buildings") You can +put any number of tags in the "add tags" box, like this: +

+ landscape cambridge "tall buildings" +

+You don't have to do this at this stage, and you can always re-tag +photos later, but if do it now, it saves you forgetting later! Try to +re-use tags that other people have used, then all the photos can be +found under the same tag. Use the tag list to find existing tags. +
+

+Suggested tags +

+
+
File
+
+[% INCLUDE footer %] diff --git a/templates/photo/view b/templates/photo/view new file mode 100644 index 0000000..33b562b --- /dev/null +++ b/templates/photo/view @@ -0,0 +1,86 @@ +[% INCLUDE header %] +[% SET tab = request.params.active || "comment" %] +[% SET url = base _ "/photo/view/" _ photo.id; %] + + + + + + + + + +
+

[% photo.title %]

+
+[% FOR tag = photo.tags; + ""; + tag; + " ("; + tag.taggings.size; ")"; + ", " UNLESS tag == photo.tags.last; +END %] +
+[% IF photo.albums %] +In albums: +[% FOR album = photo.albums; %] +[%album.name%] ([%album.photos.size%]) +[% ";" UNLESS album == photo.albums.last %] +[% END %] +[% END %] + + +Photo shot on [% photo.shot.ymd %]
+Uploaded by [% +photo.uploader %] +
+
+ [% SET sizes = request.config.sizes %] + [% IF request.params.exists("scale") %] + [% SET size = request.params.scale %] + [% ELSIF request.session.scale %] + [% SET size = request.session.scale %] + [% ELSE; SET size = 1; END; %] + +

(Original size [%photo.dimensions %])

+

+ Size: + [% SET i = 0; WHILE i < sizes.size %] + [% IF photo.is_bigger(sizes.$i); %] + [% IF i == size %] + [% sizes.$i %] + [% ELSE %] + [% sizes.$i %] + [% END %] + [% END; %] + [% SET i = i + 1 %] + [% END %] +

+ [%# Now put it back in the session %] + [% SET request.session.scale = size %] +
+ +[% MACRO do_tab(tabname, label) BLOCK; %] +
  • + [% IF tab == tabname %] + [% ELSE %] + [% END %] + [%label%] +
  • +[% END %] + +
      + [%do_tab("comment", "Comments") %] + [%do_tab("exif", "Photo info") %] + [%do_tab("tagedit", "Edit tags") %] +
    +
    +[% +IF request.params.active == "tagedit"; INCLUDE tagedit; +ELSIF request.params.active == "exif"; INCLUDE exif; +ELSE; INCLUDE comment; END; +%] +
    +[% +INCLUDE footer; +%] diff --git a/templates/picture/view b/templates/picture/view new file mode 100644 index 0000000..976b786 --- /dev/null +++ b/templates/picture/view @@ -0,0 +1,7 @@ +[% INCLUDE header %] + +[%# Scale to 800 across by default, else scale to appropriate size %] + + diff --git a/templates/recent.rss b/templates/recent.rss new file mode 100644 index 0000000..51be582 --- /dev/null +++ b/templates/recent.rss @@ -0,0 +1,22 @@ + + + + Memories photostream + [%base%] + Recent photos from [%base %] +[% FOR photo = request.recent_uploads %] + + [%photo.title|html%] + [%photo.shot.strftime("%a, %d %b %Y %H:%M:%S %z") %] + + +[% FILTER html %] + + [%photo.title|html%] + +[% END %] + + +[% END %] + + diff --git a/templates/rhs b/templates/rhs new file mode 100644 index 0000000..e23114a --- /dev/null +++ b/templates/rhs @@ -0,0 +1,33 @@ + +[% IF ! request.user %] + + + +[% ELSE %] + + +[% END %] + + + + + + + + + + + + + +[% IF request.user %] + + + + + + +[% END %] +
    Login
    [% request.user.name %]
    List users
    View all tags
    Recently uploaded
    List albums
    Home
    Upload
    +[% INCLUDE calendar %] + [% INCLUDE tagcloud %] diff --git a/templates/static/1-s.gif b/templates/static/1-s.gif new file mode 100644 index 0000000000000000000000000000000000000000..304f6ce9a39bc7cd65fac774f0902818271a9e8d GIT binary patch literal 646 zcmZ?wbhEHb6k!lyc$Ud<V-RmW{ZcMv_`#ezH)q_vHDleHitAUW+`fJL>7#ic-Y#7*Kj_8N z`KM3z%$gOjZcYAyeWmNy7OYsFaByGinN!V^COTie+;!n>+wr5F2ltoGn;WoWTm9t8 zF4L#`Enk+nV|)Io<4q6l&Ny_iY~S9ZJ-eE&UYfLbcZHXi*OVzf2llp1o#M53ch#o# zRrBUXZr+qSe_qV8r4ch`_+7u+Gi8eVvSm@*w&uKkv0(9{uyt#brcUvB@^HqE?FIL4 zPxAKmet2*8>63LQj&)U6S5KerwRvO4`n6?OE>4;?GwAKB#dGIGpFi8SbZN}X=L;`i z?3_0*bj!w?RV(r~tgF0wxo5@<{~6N*H*d;1dZ>NYOz+R1KOa7Pc)|pSkMEZK|NozX zVxahwg^__FlR*b$5-3g>*dI4!HZ^6mwzZ3;Hg~u8wxxCTw7NK`7(}r!wNGen^)gfs zXJu7l7U-SR#w3?y!ojF2$kLbA?wh`2hm$8WTVK0?u8hSFd!69O{i|4|<%81AZ21{a zwXsR*87m}M`-xv|XAsxW3Q1;u(8j>%oF1kq__FmiUwWeXi%+iucgPCQdii3m<)fud z>l^e>Jb0C~VPdPZO^wJw(UgN6I&S*}4m7Aa&Wy^KkkT+I`(Tr?_O>S(0jiBnCh`|K y5|Wf!`M5+R3?3*wKG>qlb%x_tN23EHC;KEN2ZeIX#cv)ATQC;r9U=0A#aVP5l literal 0 HcmV?d00001 diff --git a/templates/static/1.gif b/templates/static/1.gif new file mode 100644 index 0000000000000000000000000000000000000000..0eb416fb09f3479f13469ed279f6ed1cac254f93 GIT binary patch literal 649 zcmZ?wbhEHb6k!lyc$UEM`o)4XryCwUdi3kpuVY6m7cB~&Gskz@G`FXZW**pIeE06% zo7Z|KOmJ*zahg55Z0qK<> z%!z*g{_Tkqi+AqqPDt=tyg1|joyjdN&VT;=Uc5LhD=VYByY%<(ABPUDoj8#gv3BzU*908MVFuMfCz&!j0_A33_2i7Kykvr{;VOPsYzK&PRHL-!9Y(&ym>-` zxm5hrX;U3MMT92G`b=LC&tt;G-0U$eHdauWWg#EevH<(3Y@Cej@v#eeG?~=Rrm-<@ z=VW1BDC!nDoj>mUg@y6%`U}`&Ss2e>3XQoG%X)jEtKI#Facm2fr0>T+S`e)AmVsgC zf~df^ig95Jy(8}PF?{%>aD`9N#i_CS*(;%bZSequ6`~0Tne;i>*c1#Na<}js9|%|w zw32~=<$@nmgup{?J|3$B9s&;(noYa~rsQl?aJaz0s;hNpjUsDvYeX{}M@CYTM-LnC SoD(ksm5z4>B``5ESOWkt2L+7) literal 0 HcmV?d00001 diff --git a/templates/static/2-s.gif b/templates/static/2-s.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6c405c13ccfa2026687c9728f2d028baf79f783 GIT binary patch literal 718 zcmV;<0x|tZNk%w1VH5xq0Oo%H%*u_(#)-+te%IBE*3*-Ge0-CWM4z5gqM=>b*N>Z; zOwrDTo10O$wSK3jb4p4|xVLNT=%VcDqu<<`ySahr<)85FrQOggVWHF%gKz}+uQEzq?MINmX=B5 z;h0QJOyJ#`%*un#%!R(ZdZwjV)Y6Htu6gO_p`)Q?xVCoO*_E!XWS^a7+Sin(rdYVP zZL+U=qoP*U(~6drO~Jo++}W6zmrBRRe5R#m&C7+=(~8&BkgcnC&&`U#!NIk%e3+M2 zxwvrG)s&Z(RJgW(si3($9+P=%B;EhO@D0x3z4eqG+e4YP`96zPy9i){e%+iKnJp<>H*Hsb;CD zUYeOpl$1=CmQSIeX4TV-qoQTd&5z8=f%Eh8!^6XnkU;V7rvLx{A^8LW004ggEC2ui z02BZe000O7fPaF5euajIDSLy9hmD4Oij0LBK{PZbMhOxYg^+`W18`n3WFAT|F$o-; zo}dX^K5riza%W6A1Dk$)hAk!+bA7_YEMqVl9E}TiXdiubJ9cSWeIYUv5seZ88!UZN zHEtvU27L%8HjNk+I>J_L*logC0TqrIAUIb`C>3Q8eZn{(ku$GUYJxwH3=->f_hZhqr5P6}YZ=|-oK>Be}z*8UqJJ~vH ATL1t6 literal 0 HcmV?d00001 diff --git a/templates/static/2.gif b/templates/static/2.gif new file mode 100644 index 0000000000000000000000000000000000000000..251beccdf4ce570d9458afa78f2acf0be2ef05df GIT binary patch literal 694 zcmZ?wbhEHb6k!lyc$UC$^IFfeX>N-a1<#q|d+ccCqeqW^{rYwJV%yV4Gq-L|yL@_7_i>;MmgQ^!xYkKY#x8^*Q9_<-LFZ{>StX2sOi zInJNowQN~tLV|Zff>(EUNqv35p+jr`{Q13Y+qU|8hb2oIHf(5~H!mhFEp5q?w8loa z_wV0kWH>KgoVIP-mLo?t%$XB?_wKRZzkhUhm+sinRaY0#*y!5d?^sgewqQYbak1;1 zIZV^t8+SYW@~1q%Yz4JGBVP(Z{NOiXLnj!Ku1T%y0rMjSr{1@5*TzqmVn}ff&G6&LQ|8mM7X4ikAk_c4S(~5 zgb>~Msne!vIS30(^p~5yAf8vAm905oDr4;GSZ>bP>0(^Vl+@yxnV6z@qGFkuV;QIN z>aaRnO^uCWVUOX6V-Q(2O;p`!>aM8hxM&83^D*%orW&~3h>f}ZIG!bL?=(Z{X-qM3 zaj)Mp9GdEGF`biP#~bN_1KiEt8ci)y5fhj+`0Si&FESmFo6fkvDud(d(*t69oGN+~ znY!edn11gth)B?M;Z$GAu_SqB&*{cO(^WPTE;=|g<%;diwdB-3)UA`CcH_dL+|!Ne z-}VT6_`0;6MJho-WJ80?qNNLP<(i3jU$^d*B^zXly+wJz)1;` O6AyW58Z*%84-kVHJOp=mB?(3xK=b_`^oP2zIpPy5im`d;LrI(jZl$1rEo>Roac+t;= znV448(uv#K+mez-)zXsV;h5;pe)j%V`PY4@*5JYj4;!qqi z1{CzMQ((#q4J`U_Z~_vxdVixvexdh}@P=CohGejV6feE-hm zY17=!oNl;$vF+~NyAvijwzN1MJ6ieY&!4_NhmH=f_wU~?UApx5@87d$m*wTvV0!m8Uwr$&1U+=JEN7voE$BTeFT zrPb91Y}n9z=FHYflbq}81Mc5HwRmyH@83TT9a=koepf~Y(B$Zr7RSa$x4JsV_wV0! zcb8;jI5#%BzI*q&uFh%3jL80e$Akp$Wy>-bEa=|2v8l7ObLrBC`g*5{6P|VDv zVa1B5kMEXEnBegL|9=Kr0>z&!j0_A33_2i7Kykvr{=XrismanTT1G+B$yVK4ym>-` zT1foVX;ZbVM1>~mMNMB2&mY0Y(X2ZyHfHsz7{+N5e9Ii|r^YY~vd6^6Gsdo8VvbFsuR?3w0cI*mJ)A&xsfmWg5CbO-4LoXo5-=XheC zP4kmq7{keXhUtP{r-jg}N#d+0Ie2z_XZ36kIIvH|W5e5qr8;3jvLDhf&e+5Z5#oeC+9?OiWDc=%V4?o9gGG;@_O`?WN`7 zp6BGB!irWe!jeeq@!8J#EGV+TG!Q-mzPY?&W69eblTUD(9MR?&xxR)T&k&I%gKM( z)sV}{jHab=oSRjYltt3ejiaGx#l(M`n^C8xYOAVi$i|ASs&?MnnV6STy}N$V&XCm7 ziKC)wo}O9O)Qh;bf6B;ym6S-x#(b5PO_h{R%E*hIolwQYc%`ISk)+L+MIkDi`W z+SrzwnM;zAM90N@>F1%=)04r!dXkbz!@+{7r)!mzN}-@;#KL&b&4`zlOPZNlpq^Sw zOH1C{lEA%$l$1xWtz_uspT50zxwnABz=qY*l9G}`ot#pbmrkapSf{3Dyt;I?vUHxE zTfe=7o10GN`4&7jD`#xqV!txhJu1i zg$Uru)5y(|8f}cgSRtVRCISNZ3_Y{}!yGh1J|G#PpaaxAf~FQ4pum6w2L=$-DG){g Osjx%^nSE6h2mm|HBwf`2 literal 0 HcmV?d00001 diff --git a/templates/static/4.gif b/templates/static/4.gif new file mode 100644 index 0000000000000000000000000000000000000000..b42183c4d58516c8969f6c2162c0084e2bf66b92 GIT binary patch literal 668 zcmZ?wbhEHb6k!lyc$UDhVnx)twF$d-=AJp-@aWN_U%!4`zSy>PbK2_{3!XljdH3$! zMT>&(-0c;8o?Pc68O%IW;!AWoEk6 z)j1wIwD!!It!Zfi_4NTA9UXV?9{cm>cYnX*ym>LdfB$G{ao(_@dGTVP8@6oR*fedL z+s$h|AKxvTFu~#f|NjiM1d2ad7#SE67<53EfZ~LK{bxf$Q&X^lvZSn|Lxj4FSo4Gg zOPlzq)23=V2?$TLlAFFDp4XX$wb^!I3=?0>bWyHlif#*;)-K>xWeL+>$j%U}wopVR zXdwe5b6o7gcq5Mmf=rBYr_KaePhZ7wGLG$xMd-9!OjkHgFATSz8pF=W9>*cb#<6X> zeB{)(m*W`XIpesUuHN{>%Fw{dv%>HP`+09B_GuXwKM%3a6laSy`e&Sw;Bdf8sYW0% ztbpN&w^>v~#wCW320e~lu~i!sxgKXOeBhueDjw4?(_sOV=%lG~I-QM;4GWmK m`T`VAJ~_(Dvw=-iVFBw=9#tU~m5U!(+yupz9$;Z&um%8SXA2Mj literal 0 HcmV?d00001 diff --git a/templates/static/5-s.gif b/templates/static/5-s.gif new file mode 100644 index 0000000000000000000000000000000000000000..00f59be3ff2234f20902edefbbb7a92c32e99382 GIT binary patch literal 710 zcmV;%0y+IhNk%w1VH5xq0Oo%Hv#@&E*Otx8j>pD*z`lFg){wrugOQO#wX|xToK=~b zO{b=6*VT=al17=BQI(ZQ?dqe{(uwTpqwwve?(3vXOibqEo_u_K;N6<*%24;GCD1Nyx^EmX=B9 z|IVw{^;%E*h#$bZ(< zi>#_}qM=o$q-LU`T$h$jo0?Llq;R#ee8a(c!oYpR!g$8Sd$qK0(a(vfr(B$yQL(UT zvaoNcrfuNfm)h8pl#@s3<)4+5MX;}Cvax5jv~st#ew33*`61g0HQ3-P)F$n^C{L zgPE95nwm_ot#+@jaG{}9$;XJUtZ&@enDg`V!^6XnkU;V7rvLx{A^8LW004ggEC2ui z02BZe000O7fPaF5euajIAbW$0hmD4Oij0O_J|+>DBR3Eekb{Li5gG#)8y2QLOdAw_ zorV!`ItX__9<^j4C#$T7qG~FAz`$iZDHD!<5m+334PjqqYXC1T$9^MiEHN%NL3U7h zBoNgaV|_4v2M-D~NClh65i`pNF%G~91UC}KjZ!yHIf}f|lE(p+GDy7WIz)lNl@%*O zkkA9>L7y`LBs4;igifC<8U189!lKWD4;>mYKwu6)32`WtaM*D&shxp;n>m2r;lbXS`>U>fAOP7kAD67HD`|R z<%?}+PB(1boObu_-3b#Mckj$?X>sc7bNKV;&-?f9XU{I{=h6B4{LGhOQH95-xezI*rhf(700-@o0lqig&2?GGND zNly>>^XK=wcdzHniMoIPR7;C3s$U%nlQoP|Ns9Cv;>MjSr{1@5*TzqmVn}ff&G6&LQ|8inZHb!y@F|=g?RIX z1Z&y&sne#qdWZ;54Dp*josp4Wn}f4Cd@5U99P^qrY`jxN`Ib9GO^u6ZW1PNbD!&GY zv&*!#ObjunVz~EC6;lb`$9^)FHHL|2ft2Mw?wD9!X0`=WgQTZ33p`-uW@q0uJz9NV zTx@I%!*`yzbMcOHuM(vfENHZ2`nZq7GpKLQQs!%H5m`xx#2Fa4ba)-g4osRTaEv43 z^K(~+=`A)jD^46;(B06pTdYKpLD;*S+fc5C(_!stCMFiHh;H?TT-*jC(?Wt68XFpN zSlE7OHy&i2!O5XzpjqyDh(|(FfWzy-gErQ6@fjx$Ojvkr0Skv<-;xtbN=_^qUUqvV M79JLv;lN-G0JKUKSpWb4 literal 0 HcmV?d00001 diff --git a/templates/static/6-s.gif b/templates/static/6-s.gif new file mode 100644 index 0000000000000000000000000000000000000000..226cc050ef2679a57205179d0beb83c127d2608f GIT binary patch literal 719 zcmV;=0x9!q$9|KONuHfqm6b@myKtJATI}hg?(3xQ?4{@ApOlnE*VT+nOiY)TN$KaI zl9EGwe0=cjrRCzD$HjZw+uNR9KY!+*-ii_Xl6=Hs5|<)7;3q3GtIl95B% z*N@K2j+2u_%gTnPq-v|GX|=L^kVwtvyjirUzf*VUA}x^I}5PQ1Ewrlnfa&yk*< zP@kS$ySagzn@+^TdZnaY(aw&ms$s;!e%#rUz`cUFwsGX*o8#b|uB~R$(2SXwRLRGS zt*ddbt$3oKUbM1tsHSqexO~dUfXvE+&C7?at7qZfo1vgvm6b}Sq-D;_jKjfqu&-*X zscpu@fZyDj!@+r=pI+_iqo1Esot$5vo?gese7?Mcv#@)qsA`#*O~Af)nwd?Mlt-eX zSiHJ&v9ETpu6eAgbd!@ulaofLreD_6lk@ZQ!^6XnkU;V7rvLx{A^8LW004ggEC2ui z02BZe000O7fPaF5euajIA$x<1hmD4Oij0RC4Qc`gIV%)?kb{#ABy(a3FeeKK6`YEb zEe1S6A|ha32nrjie5_;_eQ_gweR($u788vD4NVttF?MVZeH>XfAI6gkMHg*hQ%OvH z4s|^in}=UF7cX}J8fO|1XmmFd9*q%Az%(pz03$3;Rcz2}ltYXL4h1AonX#o$0U0Nb z3^YWdggOaP7~n861mTbz<;SbqD6*eGn!GHh(6M8FJ9E0> z*wM-f6CCf}y}NYj(!M^2*|W=9TAbd$f1j6^*U{ni=g*(tzkkn}6Lsdy*0i*=;$qjj zI>-0#-!56wFma-DW24*R#cA8NZJ9L5dC8Kr6DJnmzkll8yVu>_C3EIP&zcppZQHh; zJG&Pw=-#oTD?L4+ySuc$KA^tdsiefMzTV;F$t4>$G#@##p{2#Sr3L7Q<8^gTbLU1s zcyJ~wD`Woru6grfX3U6Oy0qc())%w{JhNzj)3Z-`6h|Jbg6t z*Cm+*ASHWvWWk7~)u%BU$32qSo`+u{tSl zi(}+ukByCCj%Q$s7YX;D9v8EZE74jWw@ zPB-fQ(yH_xWKfN_})pQ6rw)be*_9SSsstGVy0|14*8!`X@ literal 0 HcmV?d00001 diff --git a/templates/static/7-s.gif b/templates/static/7-s.gif new file mode 100644 index 0000000000000000000000000000000000000000..d60763a1ffdfaf60b68e1b0cd6bf106885571fc4 GIT binary patch literal 673 zcmV;S0$%+`Nk%w1VH5xq0Oo!G@9d@2(uqt=OniKN-`tw)>7&!piRtH|;@_Oi%7fe4 zmz|tj!NI}g;hoLOgp-m+$Hj^0=Ahf#+w16})zgZgpH%ASq3-LXm6b^5pk|YjOPQEYm1!ySab6xq+>#cdM#h$;XSQrfSQ{ zjGUWKnV3qIluWa*d$X}=LE<3^{{+9R@984h{*YUI`j>kPjIyq%73IM@uSaEO2lnp%DcS z7=Ex((5{gHJ;DrOdBW$55QIht_(5u@fPxw?bLY(Qy?giW z{X3HmA;|e_L1QIB}x$;>Bra&TQSVq51y(Q*-7-ZQZ)*$dL{2-o1YC;LQB_UCWkb&YBgI zkl?*^X+uUvT1$)Lf(6|tPAuNBqpPmYY2(JGB}*C(9a_6|X=Y=iTV|%q+_}-)w{M>_ zC%V2q;O^aH+qP|)G|9Q8#rf>n?TZ&@WMyS^cbA+zxumJ)onbBO}8( zA;GJ@-s#Vu-^InQzkmPOwr$(ao!v{8r1keZ-o1N##*E0461TLpfX>d&Wy`W(zgY0` z-Le%cq9#mm`2YVu1C4>=PZmZ7hIj@YkUgL{VPOB;5Z~0~7aA00sqCcaC?noHAzocG zZtAqDTB<_A6Ak31FNovOVPbD~jpJltj9t4fmXRfvk87EdeOxRH$C~xbEIWBLm;!>Q zGO|WT$HYW4FmT7jP8C(LoyKwI)|qp>%+p*9r!&N`vOVYLj^>X>XhGE(hwgnzi z(^m<`G4n>V?u%vGq#UBka!R13=;Ofz@l?hejaf#A6PWebmbF$fDTOqpY~oQfOk@q2 z&cqm_{v*>!5RSVz6Htv literal 0 HcmV?d00001 diff --git a/templates/static/8-s.gif b/templates/static/8-s.gif new file mode 100644 index 0000000000000000000000000000000000000000..b648bdd4bb5f7bff4961a016bf6ddaa44afeae07 GIT binary patch literal 731 zcmV<10wn!MNk%w1VH5xq0Oo%H-P)7T&4!wpP}9+gs;OSVzkKQEp{%NI*w&TN&WxU% zSHHb=%E*G@-kXz>MzgVYot$3R)s4^0hrPRbm6b-Kpk9@fNT{c8nweDZ?4|JSrS0mY z?CGOSOiYrJM0|XF?(3xD-<<2{qLY(E#lnZ^<)72gk+rmI+uPgg=%CowkJi(Qt*de5 z;hnLsdY6|;-P)Ms;h3nWV8p?PudZjIpjX=0kf^6zl#@l((~#EFljGo=pPp2fl}*jd zh34a(tgB(czk#r?b<4?qyt;DI&yk{_WTvHIwX%G}!FR^QfX2g!ySZ=D(1*&$gq)jG z!@!2b!-MDKpUTLK%*uh1kwe|umcP7#tE*tSw{xngX2`~hmX%Ahv1zifZQ9t9udR00 z)QjKTm9DIKxwvq`z<gFehC!JT)~mIX)#IpN26u3N7Y}6x6Uzq(zl|9xFMSv?N)m4`XD&J%o*Hc+AmH2x9DVc{$pa%=qZ9#v zjBwxp!?HdQ)K~%5Xh;Nv5a=8bQm2Q5D|b2_0-%COA30-4ByeIPjfXV|#2s4kklh%(04lQ&{ApvE^k}X9VY|zU`P+vb8M3it7B18)*02xQ( NtJaYr&3^&`06WsuY|H=v literal 0 HcmV?d00001 diff --git a/templates/static/8.gif b/templates/static/8.gif new file mode 100644 index 0000000000000000000000000000000000000000..036dbb682fcde2aa120eafcd122e7bb969cdac8c GIT binary patch literal 713 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 literal 0 HcmV?d00001 diff --git a/templates/static/upload.js b/templates/static/upload.js new file mode 100644 index 0000000..0b033c6 --- /dev/null +++ b/templates/static/upload.js @@ -0,0 +1,82 @@ +String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,'') } +String.prototype.escRegExp = function(){ return this.replace(/[\\$*+?()=!|,{}\[\]\.^]/g,'\\$&') } +String.prototype.unescHtml = function(){ var i,t=this; for(i in e) t=t.replace(new RegExp(i,'g'),e[i]); return t } +function Suggestions() { this.length=0; this.picked=0 } +var suggestions = new Suggestions(); +var tagSearch='', lastEdit=''; +var h={}, sections=[{},{},{},{},{},{}], selected={}, currentTag={}, +e={'<':'<','>':'>','&':'&','"':'"'}; + +function init () { + document.onkeydown = document.onkeypress = document.onkeyup = handler + h.suggest = document.getElementById("suggestionlist"); + h.tags = document.getElementById("tags"); +} + +function handler(event) { var e=(event||window.event) //w3||ie + if (e.type == 'keyup') { + switch(e.keyCode) { + //case 8: //backspace + //case 46: //delete + case 35: //end + case 36: //home + case 39: // right + case 37: // left + case 32: // space + hideSuggestions(); break + case 38: case 40: break; + case 9: break; + case 13: break; + default: + updateSuggestions() +}} + else if (e.type == "keypress") { lastEdit = h.tags.value } +} + +function makeTag(parent, tag, js) { + parent.appendChild(document.createTextNode(" "+ tag)) +} + +function updateSuggestions() { + while (h.suggest.hasChildNodes()) h.suggest.removeChild(h.suggest.firstChild) + if(!getCurrentTag() || !currentTag.text) { + hideSuggestions(); return false + } + var tagArray = h.tags.value.toLowerCase().split(' '), + txt=currentTag.text.trim().escRegExp(), tagHash={}, t + for(t in tagArray) tagHash[tagArray[t]] = true; + + var search = tagList.match(new RegExp(("(?:^| )("+txt+"[^ ]+)"), "gi")) + if(search){ + var i; + for (i=0; i 0) { showSuggestions() } + else { hideSuggestions(); } +} + +function getCurrentTag() { + if(h.tags.value == lastEdit) return true // no edit + if(h.tags == '') return false + currentTag = {} + var tagArray=h.tags.value.toLowerCase().split(' '), oldArray=lastEdit.toLowerCase().split(' '), currentTags = [], matched=false, t,o + for (t in tagArray) { + for (o in oldArray) { + if(typeof oldArray[o] == 'undefined') { oldArray.splice(o,1); break } + if(tagArray[t] == oldArray[o]) { matched = true; oldArray.splice(o,1); break; } + } + if(!matched) currentTags[currentTags.length] = t + matched=false + } + // more than one word changed... abort + currentTag = { text:tagArray[currentTags[0]], index:currentTags[0] } + return true +} + + +function hideSuggestions() { h.suggest.style.visibility='hidden' } +function showSuggestions() { h.suggest.style.visibility='visible' } diff --git a/templates/systemtag/list b/templates/systemtag/list new file mode 100644 index 0000000..9a7361a --- /dev/null +++ b/templates/systemtag/list @@ -0,0 +1,36 @@ +[% INCLUDE header %] +[% PROCESS macros %] + + +[% WHILE objects.size > 0 %] + + [% SET minilist = objects.splice(0,7) %] + [% FOR tag = minilist %] + + [% END %] + +[% END %] +
    + + [% SET photos = tag.photos %] + [% IF photos.last %] + + + [% ELSE %] + +

    (No photos)

    + + [% END %] +
    + [% tag %] +
    + + + +
    + [%photos.size %] + photo[%-"s" IF photos.size != 1 %] +
    +
    +[% INCLUDE pager %] +[% INCLUDE footer %] diff --git a/templates/systemtag/view b/templates/systemtag/view new file mode 100644 index 0000000..42e885d --- /dev/null +++ b/templates/systemtag/view @@ -0,0 +1,14 @@ +[% INCLUDE header %] +[% PROCESS macros %] +

    +[% IF tag.name %] +[% tag.name %] +[% ELSE %] +[% FOR tag = tags %] +[%tag%] +[% ":" UNLESS tag == tags.last %] +[% END %] +[% END %] +

    +[% view_page_of(photos) %] +[% INCLUDE footer %] diff --git a/templates/tag/list b/templates/tag/list new file mode 100644 index 0000000..9a7361a --- /dev/null +++ b/templates/tag/list @@ -0,0 +1,36 @@ +[% INCLUDE header %] +[% PROCESS macros %] + + +[% WHILE objects.size > 0 %] + + [% SET minilist = objects.splice(0,7) %] + [% FOR tag = minilist %] + + [% END %] + +[% END %] +
    + + [% SET photos = tag.photos %] + [% IF photos.last %] + + + [% ELSE %] + +

    (No photos)

    + + [% END %] +
    + [% tag %] +
    + + + +
    + [%photos.size %] + photo[%-"s" IF photos.size != 1 %] +
    +
    +[% INCLUDE pager %] +[% INCLUDE footer %] diff --git a/templates/tag/list_js b/templates/tag/list_js new file mode 100644 index 0000000..af9b159 --- /dev/null +++ b/templates/tag/list_js @@ -0,0 +1 @@ +var tagList = "[% FOR tag = tags; tag | html; " "; END %]"; diff --git a/templates/tag/view b/templates/tag/view new file mode 100644 index 0000000..8ce4707 --- /dev/null +++ b/templates/tag/view @@ -0,0 +1,28 @@ +[% INCLUDE header %] +[% PROCESS macros %] +

    +[% IF tag.name %] +[% tag.name %] +[% ELSE %] +[% FOR tag = tags %] +[%tag%] +[% ":" UNLESS tag == tags.last %] +[% END %] +[% END %] +

    + +[% view_page_of(photos) %] +[% INCLUDE footer %] diff --git a/templates/tagcloud b/templates/tagcloud new file mode 100644 index 0000000..bd46663 --- /dev/null +++ b/templates/tagcloud @@ -0,0 +1,4 @@ +

    Popular tags

    +
    +[% request.tagcloud.html(75) %] +
    diff --git a/templates/test b/templates/test new file mode 100644 index 0000000..b5f5031 --- /dev/null +++ b/templates/test @@ -0,0 +1,2 @@ +[% INCLUDE header %] +[% INCLUDE footer %] diff --git a/templates/user/album_list b/templates/user/album_list new file mode 100644 index 0000000..59bcad0 --- /dev/null +++ b/templates/user/album_list @@ -0,0 +1,41 @@ +
    +[% IF request.user == user %] +

    Albums

    +
    + [% IF user.albums.size > 0 %] + + + + + [% FOR album = user.albums %] + + + + + + [% END %] +
    Name Private? Delete?
    [% album.name %] + +
    + +
    + [% END %] +

    Create a new album

    + Name:
    + Private?
    + +
    +[% ELSE %] + +[% IF albums.size > 0 %] +

    Public albums

    +
      + [% FOR album = albums %] +
    • [% album %] + [% END %] +
    +[% END %] + +[% END %] +
    diff --git a/templates/user/list b/templates/user/list new file mode 100644 index 0000000..66ba34e --- /dev/null +++ b/templates/user/list @@ -0,0 +1,25 @@ +[% INCLUDE header %] +[% PROCESS macros %] + + +[% WHILE objects.size > 0 %] + + [% SET minilist = objects.splice(0,3) %] + [% FOR user = minilist %] + + [% END %] + +[% END %] +
    + [% SET photos = user.photos %] + [% user %]
    + [% IF photos.last %] +

    + + [%photos.size %] + photo[%-"s" IF photos.size != 1 %] + [% ELSE %] +

    (No photos)

    + [% END %] +
    +[% INCLUDE footer %] diff --git a/templates/user/view b/templates/user/view new file mode 100644 index 0000000..b3cadec --- /dev/null +++ b/templates/user/view @@ -0,0 +1,7 @@ +[% INCLUDE header %] +[% PROCESS macros %] +

    [% user.name %]

    +[% INCLUDE album_list %] + +[% view_page_of(photos) %] +[% INCLUDE footer %] -- 2.39.2