Compare commits

...

No commits in common. "master" and "gh-pages" have entirely different histories.

412 changed files with 3259 additions and 23935 deletions

19
.gitignore vendored
View File

@ -1,19 +0,0 @@
.bundle
.rvmrc
db/*.sqlite3
log/*.log
tmp
.DS_Store
doc/api
doc/app
config/database.yml
config/settings.yml
config/deploy.rb
config/deploy
Capfile
public/thumbs
public/uploads
public/assets
vendor/cache
.idea
.sass-cache

1
CNAME Normal file
View File

@ -0,0 +1 @@
balderapp.com

62
Gemfile
View File

@ -1,62 +0,0 @@
source 'http://rubygems.org'
gem 'rails', '3.2.7'
gem 'sqlite3'
gem 'mime-types', :require => 'mime/types'
gem 'carrierwave'
gem 'dynamic_form'
gem 'kaminari', :git => 'git://github.com/amatsuda/kaminari.git'
gem 'princely'
gem 'unicorn'
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'twitter-bootstrap-rails', :git => 'git://github.com/seyhunak/twitter-bootstrap-rails.git'
gem 'ajaxful_rating_jquery', :git => 'git://github.com/greendog/ajaxful_rating_jquery.git'#, :branch => 'rails3'
gem 'configatron', :git => 'git://github.com/markbates/configatron.git'
gem 'plupload-rails', :git => 'git://github.com/bryanmig/plupload-rails.git'
#gem 'sequel', :git => 'git://github.com/jeremyevans/sequel.git'
gem 'breadcrumbs_on_rails', :git => 'git://github.com/lloydk/breadcrumbs_on_rails.git'
gem 'russian', :git => 'git://github.com/yaroslav/russian.git'
gem "devise_omniauth_engine", :git=>"git://github.com/greendog/devise_omniauth_engine.git"
gem 'omniauth-twitter'
gem 'omniauth-facebook'
gem 'omniauth-openid'
gem 'omniauth-google-apps'
gem 'omniauth-vkontakte', :git => 'git://github.com/mamantoha/omniauth-vkontakte.git'
gem 'cancan'
group :assets do
gem 'sass-rails'
gem 'coffee-rails'
gem 'uglifier'
end
group :development do
gem 'ffaker'
gem 'machinist'
gem 'action_mailer_tls', :git => 'git://github.com/openrain/action_mailer_tls.git'
gem 'capistrano', :git => 'git://github.com/capistrano/capistrano.git'
gem 'capistrano-unicorn', :git => 'git://github.com/sosedoff/capistrano-unicorn.git'
gem 'rvm-capistrano'
gem 'capistrano_colors'
end
# -- Cloud storage
# AWS S3 support. Can be disabled if using local file system instead of cloud storage.
gem 'fog'
# -- Photo resizing
# MiniMagick
gem "mini_magick"
# ImageMagick:
#gem "rmagick", :require => 'RMagick'
# FreeImage:
#gem "RubyInline"
#gem "image_science", :git => 'git://github.com/perezd/image_science.git'
# -- EXIF
# Mini exif tool. Can be disabled. Remove exif_read and exif_write filters in photo model
gem "mini_exiftool"

View File

@ -1,341 +0,0 @@
GIT
remote: git://github.com/amatsuda/kaminari.git
revision: 82a38e07db1ca1598c8daf073a8f6be22ae714d6
specs:
kaminari (0.13.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
GIT
remote: git://github.com/bryanmig/plupload-rails.git
revision: 6d07d0f7e05d0b3fdc9b03b49d3a7c3aa1cd703b
specs:
plupload-rails (1.0.6)
rails (~> 3.1)
GIT
remote: git://github.com/capistrano/capistrano.git
revision: 62a6cb723dc583468943fc642847791fb4ad2686
specs:
capistrano (2.12.0)
highline
net-scp (>= 1.0.0)
net-sftp (>= 2.0.0)
net-ssh (>= 2.0.14)
net-ssh-gateway (>= 1.1.0)
GIT
remote: git://github.com/greendog/ajaxful_rating_jquery.git
revision: ae3314d3067d9f13a62675fa08afa4ecd31a7828
specs:
ajaxful_rating_jquery (3.0.0.beta3)
GIT
remote: git://github.com/greendog/devise_omniauth_engine.git
revision: c46d449222133f709b5f0cafc31a57f1ae208f06
specs:
devise_omniauth_engine (1.0.0)
devise
omniauth
yettings
GIT
remote: git://github.com/lloydk/breadcrumbs_on_rails.git
revision: 310c40186b97dc816e22e9be7aac3b43dcef040b
specs:
breadcrumbs_on_rails (2.2.0)
GIT
remote: git://github.com/mamantoha/omniauth-vkontakte.git
revision: b2b9f62972911ba328538368d13407b01bc9f297
specs:
omniauth-vkontakte (1.0.9)
multi_json
omniauth (~> 1.1.0)
omniauth-oauth2 (~> 1.0)
GIT
remote: git://github.com/markbates/configatron.git
revision: 7a81defa5e1fb032b5ed62754d7e6d7bfecf07a2
specs:
configatron (2.9.1)
yamler (>= 0.1.0)
GIT
remote: git://github.com/openrain/action_mailer_tls.git
revision: 4c4db7e098d54b2239c1ce7c195417552718418c
specs:
action_mailer_tls (1.1.3)
GIT
remote: git://github.com/seyhunak/twitter-bootstrap-rails.git
revision: 908e150800610138e2b48738f842afb85b3a832e
specs:
twitter-bootstrap-rails (2.1.1)
actionpack (>= 3.1)
less-rails (~> 2.2.3)
railties (>= 3.1)
therubyracer (= 0.10.1)
GIT
remote: git://github.com/sosedoff/capistrano-unicorn.git
revision: bafc12cd8235307d30b5c85259914d17c5ece2d3
specs:
capistrano-unicorn (0.1.6)
capistrano
GIT
remote: git://github.com/yaroslav/russian.git
revision: e2dde13672bcee176f8b0be364a55ac256913231
specs:
russian (0.6.0)
i18n (>= 0.5.0)
GEM
remote: http://rubygems.org/
specs:
actionmailer (3.2.7)
actionpack (= 3.2.7)
mail (~> 2.4.4)
actionpack (3.2.7)
activemodel (= 3.2.7)
activesupport (= 3.2.7)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.0)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.1.3)
activemodel (3.2.7)
activesupport (= 3.2.7)
builder (~> 3.0.0)
activerecord (3.2.7)
activemodel (= 3.2.7)
activesupport (= 3.2.7)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.7)
activemodel (= 3.2.7)
activesupport (= 3.2.7)
activesupport (3.2.7)
i18n (~> 0.6)
multi_json (~> 1.0)
arel (3.0.2)
bcrypt-ruby (3.0.1)
builder (3.0.0)
cancan (1.6.8)
capistrano_colors (0.5.5)
carrierwave (0.6.2)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.3.3)
commonjs (0.2.6)
devise (2.1.2)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.1)
railties (~> 3.1)
warden (~> 1.2.1)
dynamic_form (1.1.4)
erubis (2.7.0)
excon (0.15.5)
execjs (1.4.0)
multi_json (~> 1.0)
faraday (0.8.1)
multipart-post (~> 1.1)
ffaker (1.15.0)
fog (1.5.0)
builder
excon (~> 0.14)
formatador (~> 0.2.0)
mime-types
multi_json (~> 1.0)
net-scp (~> 1.0.4)
net-ssh (>= 2.1.3)
nokogiri (~> 1.5.0)
ruby-hmac
formatador (0.2.3)
hashie (1.2.0)
highline (1.6.13)
hike (1.2.1)
httpauth (0.1)
i18n (0.6.0)
journey (1.0.4)
jquery-rails (2.0.2)
railties (>= 3.2.0, < 5.0)
thor (~> 0.14)
jquery-ui-rails (1.1.0)
jquery-rails
railties (>= 3.1.0)
json (1.7.4)
jwt (0.1.5)
multi_json (>= 1.0)
kgio (2.7.4)
less (2.2.1)
commonjs (~> 0.2.6)
less-rails (2.2.3)
actionpack (>= 3.1)
less (~> 2.2.0)
libv8 (3.3.10.4)
machinist (2.0)
mail (2.4.4)
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.19)
mini_exiftool (1.6.0)
mini_magick (3.4)
subexec (~> 0.2.1)
multi_json (1.3.6)
multipart-post (1.1.5)
net-scp (1.0.4)
net-ssh (>= 1.99.1)
net-sftp (2.0.5)
net-ssh (>= 2.0.9)
net-ssh (2.5.2)
net-ssh-gateway (1.1.0)
net-ssh (>= 1.99.1)
nokogiri (1.5.5)
oauth (0.4.6)
oauth2 (0.8.0)
faraday (~> 0.8)
httpauth (~> 0.1)
jwt (~> 0.1.4)
multi_json (~> 1.0)
rack (~> 1.2)
omniauth (1.1.0)
hashie (~> 1.2)
rack
omniauth-facebook (1.4.1)
omniauth-oauth2 (~> 1.1.0)
omniauth-google-apps (0.0.2)
omniauth (~> 1.0)
omniauth-openid (~> 1.0)
ruby-openid-apps-discovery (~> 1.2.0)
omniauth-oauth (1.0.1)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.1.0)
oauth2 (~> 0.8.0)
omniauth (~> 1.0)
omniauth-openid (1.0.1)
omniauth (~> 1.0)
rack-openid (~> 1.3.1)
omniauth-twitter (0.0.12)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
orm_adapter (0.4.0)
polyglot (0.3.3)
princely (1.2.5)
rack (1.4.1)
rack-cache (1.2)
rack (>= 0.4)
rack-openid (1.3.1)
rack (>= 1.1.0)
ruby-openid (>= 2.1.8)
rack-ssl (1.3.2)
rack
rack-test (0.6.1)
rack (>= 1.0)
rails (3.2.7)
actionmailer (= 3.2.7)
actionpack (= 3.2.7)
activerecord (= 3.2.7)
activeresource (= 3.2.7)
activesupport (= 3.2.7)
bundler (~> 1.0)
railties (= 3.2.7)
railties (3.2.7)
actionpack (= 3.2.7)
activesupport (= 3.2.7)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
raindrops (0.10.0)
rake (0.9.2.2)
rdoc (3.12)
json (~> 1.4)
ruby-hmac (0.4.0)
ruby-openid (2.2.0)
ruby-openid-apps-discovery (1.2.0)
ruby-openid (>= 2.1.7)
rvm-capistrano (1.2.5)
capistrano (>= 2.0.0)
sass (3.1.20)
sass-rails (3.2.5)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
sprockets (2.1.3)
hike (~> 1.2)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.6)
subexec (0.2.2)
therubyracer (0.10.1)
libv8 (~> 3.3.10)
thor (0.15.4)
tilt (1.3.3)
treetop (1.4.10)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.33)
uglifier (1.2.7)
execjs (>= 0.3.0)
multi_json (~> 1.3)
unicorn (4.3.1)
kgio (~> 2.6)
rack
raindrops (~> 0.7)
warden (1.2.1)
rack (>= 1.0)
yamler (0.1.0)
yettings (0.1.1)
PLATFORMS
ruby
DEPENDENCIES
action_mailer_tls!
ajaxful_rating_jquery!
breadcrumbs_on_rails!
cancan
capistrano!
capistrano-unicorn!
capistrano_colors
carrierwave
coffee-rails
configatron!
devise_omniauth_engine!
dynamic_form
ffaker
fog
jquery-rails
jquery-ui-rails
kaminari!
machinist
mime-types
mini_exiftool
mini_magick
omniauth-facebook
omniauth-google-apps
omniauth-openid
omniauth-twitter
omniauth-vkontakte!
plupload-rails!
princely
rails (= 3.2.7)
russian!
rvm-capistrano
sass-rails
sqlite3
twitter-bootstrap-rails!
uglifier
unicorn

View File

@ -1,8 +0,0 @@
The MIT License (MIT)
Copyright (c) 2011 Espen Antonsen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

157
README.md
View File

@ -1,157 +0,0 @@
Welcome to Balder photo gallery
===============================
Made by Espen Antonsen.
Version 1.2.3 for Rails 3.2. See the rails2 branch for previous version.
[http://balderapp.com](http://balderapp.com)
Features
========
* Stores photos to disk in folders or on S3 (can run from Heroku...yay)
* Create multiple thumbnails of custom sizes
* Read and writes EXIF/IPTC title, description and keywords
* Organize in albums (as events in iPhoto)
* Combine albums in collections (as albums in iPhoto)
* Upload multiple photos
* Tag photos. Can also tag albums (actually all photos in album is tagged)
* User management with roles and permissions
* Geo-location of albums & photos with Google Maps integration.
Requirements
============
Rails 3.2
Software
Default:
- **[ExifTool]** (required for *Mini_EfixTool*). Can be disabled. Default is to read EXIF tags but not write them to the file when database is updated as writing EXIF is slow. To enable just uncomment `exif_write in photo.rb`
- **[ImageMagicK]**. *Carrierwave* can use either *RMagicK* or *MiniMagicK* (default). To change resize option the correct gem must be used (specified in Gemfile) and change included setting for Carrierwave in `file_uploader.rb`
Optional:
- *ImageScience* which requires **[FreeImage]**.
Ruby Gems: See `Gemfile`
Configuration
=============
{#configuration}
`config/balder.rb` has the following adjustable settings:
STORAGE_PATH
: Relative path to where the photos are stored. Default: uploads
Under the specified path two folders are used. "files" for original files and "thumbs" for generated thumbnails.
This can be adjusted in app/uploaders/file_uploader.rb
PRIVATE
: Require visitors to have a user and authenticate before viewing photos.
TITLE
: Title of site
HEROKU
: To be used on heroku.com. This will adjust carrierwave to save to Heroku's tmp area.
S3_KEY
: For saving files to Amazon S3 (required for Heroku)
S3_SECRET
: For saving files to Amazon S3 (required for Heroku)
S3_BUCKET
: For saving files to Amazon S3 (required for Heroku)
As these are environment variables you can easily add them to Heroku:
http://devcenter.heroku.com/articles/config-vars#rack_env_rails_env_merb_env
For a brief introduction to how to set up Balder on Heroku see:
http://blog.inspired.no/rails-photo-gallery-balder-on-heroku-and-s3-726
Installation
============
1. Clone the project from GitHub or Gitorious:
git clone git://github.com/espen/balder.git # GitHup
2. Install required software listed above
3. `bundle install` to install required gems.
4. Adjust the settings in `balder.rb` or as Heroku config variables (See [configuration above](#configuration))
5. Copy database file (not needed when hosting on Heroku):
cp config/database.example.yml config/database.yml
6. Create database user and edit database file. (unless on Heroku or using SQLite3)
7. Create database:
rake db:create
8. Migrate database schema:
rake db:migrate
9. Start up the project with your preferred web-server
For example:
rails start # or:
passenger start
Optional: add photos directly to disk
-------------------------------------
The gallery has a web-based upload tool. Alternatively you can upload files directly to the upload folder. This means you can import an existing folder based photo collection to Balder.
Put photos in containing folders(albums) in the specified gallery folder.
Hierarchy of folders is not fully supported.
This format is recommended:
./ski weekend in hemsedal/snow.jpg
./ski weekend in hemsedal/afterski.jpg
./trip to iran/beautiful girls in tehran.jpg
./trip to iran/mosque in yazd.jpg
./trip to iran/powder snow in dizin.jpg
Every time you manually add photos to disk you must scan by visiting `/photos/scan` or run `ScanFiles.Scan(false)` from the console.
Version history
===============
v1.2.3
: Rails 1.2.3
v1.2.2
: Rails 3.1
v1.2.1
: Using plupupload instead of uploadify for non-flash upload options. Can now use html5, normal form, silverlight, gears and browserplus for photo upload.
v1.2.0
: New storage path: `/uploads/files/` instead of `/uploads/`. Make sure you move your photos or adjust the storage path.
TODO
====
- Testing...
IDEAS
=====
- Themes
- Improved UX
- Mobile/Tablet friendly display using CSS media queries
Patches welcome!
Copyright and license info
==========================
This code is copyrighted by Espen Antonsen.
The source code is available free under the MIT License.
[ImageMagicK]: http://www.imagemagick.org
[ExifTool]: http://www.sno.phy.queensu.ca/~phil/exiftool/
[FreeImage]: http://sourceforge.net/projects/freeimage/

View File

@ -1,7 +0,0 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require 'rake'
Photomix::Application.load_tasks

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,59 +0,0 @@
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require jquery.easing.1.3
//= require jquery.noisy.min
//= require jquery.mousewheel
//= require fancybox/jquery.fancybox.pack
//= require fancybox/helpers/jquery.fancybox-buttons
//= require fancybox/helpers/jquery.fancybox-media
//= require fancybox/helpers/jquery.fancybox-thumbs
//= require twitter/bootstrap
//= require plupload
//= require jquery.plupload.queue
//= require plupload.flash
//= require plupload.silverlight
//= require plupload.html4
//= require plupload.html5
//= require plupload.gears
//= require plupload.browserplus
//= require_tree .
$(document).ready(function () {
$('body').noisy({
'intensity':10,
'size':200,
'opacity':0.120,
'fallback':'',
'monochrome':false
}).css('background-color', '#fefefe');
$('.icon-popover').popover()
$(".fancybox-thumb").fancybox({
prevEffect : 'none',
nextEffect : 'none',
helpers : {
title : {
type: 'outside'
},
overlay : {
opacity : 0.8,
css : {
'background-color' : '#000'
}
},
thumbs : {
width : 50,
height : 50
}
}
});
});

View File

@ -1,101 +0,0 @@
jQuery(function($) {
if ( $('.tag_list').length ) {
$('.tag_list').tagSuggest({
tags: $('#all_tags').val().split('\'')
})
}
var map, latlng
if ( $('#map_canvas').length && $('#album_latitude').val() > '' && $('#album_longitude').val() > '' ) {
latlng = new google.maps.LatLng($('#album_latitude').val(), $('#album_longitude').val());
mapInitialize()
$('#map_canvas').show()
}
if ( $('#map_canvas').length && $('#photo_latitude').val() > '' && $('#photo_longitude').val() > '' ) {
latlng = new google.maps.LatLng($('#photo_latitude').val(), $('#photo_longitude').val());
mapInitialize()
$('#map_canvas').show()
}
$('#collection_albums .delete').live('click', function() {
$(this).parent('span').fadeOut('slow', function() { $(this).remove() })
})
$("#available_albums").change( function() {
if ( this.value == '' ) {
return false
}
else if ( $('#collection_album_list_' + this.value).length ) {
$('#collection_album_list_' + this.value).parent('span').fadeTo('slow', 0.33, function () {
$(this).fadeTo('slow', 1)
})
return false
}
$.getJSON("/albums/" + this.value + '/photos',
function(data){
console.log( data[0].photo.file.album.url );
html = '<span style="display:none;"><img src="/images/delete-24x24.png" border="" class="delete" />'
html += '<img alt="' + $("#available_albums :selected").val() + '_collection" src=' + data[0].photo.file.album.url + ' />'
html += '<input id="collection_album_list_' + $("#available_albums :selected").val() + '" name="collection[album_list][' + $("#available_albums :selected").val() + ']" type="hidden" />'
html += '</span>'
$('#collection_albums').append(html)
$('#collection_album_list_' + $('#available_albums :selected').val() ).parent('span').fadeIn('slow')
})
}
)
$("#album_address").change( function() {
if( !map ) {
mapInitialize()
$('#map_canvas').show()
}
var geocoder = new google.maps.Geocoder()
var address = this.value
if (geocoder) {
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
map.set_center(results[0].geometry.location)
mapCreateMarker( {
title: $('#album_title').val(),
address: results[0].formatted_address,
position: results[0].geometry.location
}
)
} else {
//alert("No results found")
}
} else {
//alert("Geocode was not successful for the following reason: " + status)
}
});
}
})
function mapInitialize() {
var myOptions = {
zoom: 13,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions)
}
function mapCreateMarker(location) {
var marker = new google.maps.Marker({
map: map,
position: location.position,
title: location.title
})
var infowindow = new google.maps.InfoWindow({
content: '<b>' + location.title + '</b><br/>' + location.address
})
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map,marker)
})
}
})

View File

@ -1,4 +0,0 @@
jQuery ->
$("a[rel=popover]").popover()
$(".tooltip").tooltip()
$("a[rel=tooltip]").tooltip()

View File

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -1,267 +0,0 @@
/*
@author: remy sharp / http://remysharp.com
@url: http://remysharp.com/2007/12/28/jquery-tag-suggestion/
@usage: setGlobalTags(['javascript', 'jquery', 'java', 'json']); // applied tags to be used for all implementations
$('input.tags').tagSuggest(options);
The selector is the element that the user enters their tag list
@params:
matchClass - class applied to the suggestions, defaults to 'tagMatches'
tagContainer - the type of element uses to contain the suggestions, defaults to 'span'
tagWrap - the type of element the suggestions a wrapped in, defaults to 'span'
sort - boolean to force the sorted order of suggestions, defaults to false
url - optional url to get suggestions if setGlobalTags isn't used. Must return array of suggested tags
tags - optional array of tags specific to this instance of element matches
delay - optional sets the delay between keyup and the request - can help throttle ajax requests, defaults to zero delay
separator - optional separator string, defaults to ' ' (Brian J. Cardiff)
@license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
@version: 1.4
@changes: fixed filtering to ajax hits
*/
(function ($) {
var globalTags = [];
// creates a public function within our private code.
// tags can either be an array of strings OR
// array of objects containing a 'tag' attribute
window.setGlobalTags = function(tags /* array */) {
globalTags = getTags(tags);
};
function getTags(tags) {
var tag, i, goodTags = [];
for (i = 0; i < tags.length; i++) {
tag = tags[i];
if (typeof tags[i] == 'object') {
tag = tags[i].tag;
}
goodTags.push(tag.toLowerCase());
}
return goodTags;
}
$.fn.tagSuggest = function (options) {
var defaults = {
'matchClass' : 'tagMatches',
'tagContainer' : 'span',
'tagWrap' : 'span',
'sort' : true,
'tags' : null,
'url' : null,
'delay' : 0,
'separator' : ' '
};
var i, tag, userTags = [], settings = $.extend({}, defaults, options);
if (settings.tags) {
userTags = getTags(settings.tags);
} else {
userTags = globalTags;
}
return this.each(function () {
var tagsElm = $(this);
var elm = this;
var matches, fromTab = false;
var suggestionsShow = false;
var workingTags = [];
var currentTag = {"position": 0, tag: ""};
var tagMatches = document.createElement(settings.tagContainer);
function showSuggestionsDelayed(el, key) {
if (settings.delay) {
if (elm.timer) clearTimeout(elm.timer);
elm.timer = setTimeout(function () {
showSuggestions(el, key);
}, settings.delay);
} else {
showSuggestions(el, key);
}
}
function showSuggestions(el, key) {
workingTags = el.value.split(settings.separator);
matches = [];
var i, html = '', chosenTags = {}, tagSelected = false;
// we're looking to complete the tag on currentTag.position (to start with)
currentTag = { position: currentTags.length-1, tag: '' };
for (i = 0; i < currentTags.length && i < workingTags.length; i++) {
if (!tagSelected &&
currentTags[i].toLowerCase() != workingTags[i].toLowerCase()) {
currentTag = { position: i, tag: workingTags[i].toLowerCase() };
tagSelected = true;
}
// lookup for filtering out chosen tags
chosenTags[currentTags[i].toLowerCase()] = true;
}
if (currentTag.tag) {
// collect potential tags
if (settings.url) {
$.ajax({
'url' : settings.url,
'dataType' : 'json',
'data' : { 'tag' : currentTag.tag },
'async' : false, // wait until this is ajax hit is complete before continue
'success' : function (m) {
matches = m;
}
});
} else {
for (i = 0; i < userTags.length; i++) {
if (userTags[i].indexOf(currentTag.tag) === 0) {
matches.push(userTags[i]);
}
}
}
matches = $.grep(matches, function (v, i) {
return !chosenTags[v.toLowerCase()];
});
if (settings.sort) {
matches = matches.sort();
}
for (i = 0; i < matches.length; i++) {
html += '<' + settings.tagWrap + ' class="_tag_suggestion">' + matches[i] + '</' + settings.tagWrap + '>';
}
tagMatches.html(html);
suggestionsShow = !!(matches.length);
} else {
hideSuggestions();
}
}
function hideSuggestions() {
tagMatches.empty();
matches = [];
suggestionsShow = false;
}
function setSelection() {
var v = tagsElm.val();
// tweak for hintted elements
// http://remysharp.com/2007/01/25/jquery-tutorial-text-box-hints/
if (v == tagsElm.attr('title') && tagsElm.is('.hint')) v = '';
currentTags = v.split(settings.separator);
hideSuggestions();
}
function chooseTag(tag) {
var i, index;
for (i = 0; i < currentTags.length; i++) {
if (currentTags[i].toLowerCase() != workingTags[i].toLowerCase()) {
index = i;
break;
}
}
if (index == workingTags.length - 1) tag = tag + settings.separator;
workingTags[i] = tag;
tagsElm.val(workingTags.join(settings.separator));
tagsElm.blur().focus();
setSelection();
}
function handleKeys(ev) {
fromTab = false;
var type = ev.type;
var resetSelection = false;
switch (ev.keyCode) {
case 37: // ignore cases (arrow keys)
case 38:
case 39:
case 40: {
hideSuggestions();
return true;
}
case 224:
case 17:
case 16:
case 18: {
return true;
}
case 8: {
// delete - hide selections if we're empty
if (this.value == '') {
hideSuggestions();
setSelection();
return true;
} else {
type = 'keyup'; // allow drop through
resetSelection = true;
showSuggestionsDelayed(this);
}
break;
}
case 9: // return and tab
case 13: {
if (suggestionsShow) {
// complete
chooseTag(matches[0]);
fromTab = true;
return false;
} else {
return true;
}
}
case 27: {
hideSuggestions();
setSelection();
return true;
}
case 32: {
setSelection();
return true;
}
}
if (type == 'keyup') {
switch (ev.charCode) {
case 9:
case 13: {
return true;
}
}
if (resetSelection) {
setSelection();
}
showSuggestionsDelayed(this, ev.charCode);
}
}
tagsElm.after(tagMatches).keypress(handleKeys).keyup(handleKeys).blur(function () {
if (fromTab == true || suggestionsShow) { // tweak to support tab selection for Opera & IE
fromTab = false;
tagsElm.focus();
}
});
// replace with jQuery version
tagMatches = $(tagMatches).click(function (ev) {
if (ev.target.nodeName == settings.tagWrap.toUpperCase() && $(ev.target).is('._tag_suggestion')) {
chooseTag(ev.target.innerHTML);
}
}).addClass(settings.matchClass);
// initialise
setSelection();
});
};
})(jQuery);

View File

@ -1,91 +0,0 @@
/*
* Style by Rogie http://www.komodomedia.com/blog/2007/01/css-star-rating-redux/
*/
.ajaxful-rating,
.ajaxful-rating a:hover,
.ajaxful-rating a:active,
.ajaxful-rating a:focus,
.ajaxful-rating .show-value {
background: url("/assets/ajaxful_rating/star.png") left -1000px repeat-x;
}
.ajaxful-rating {
position: relative;
/*width: 125px; this is setted dynamically */
height: 25px;
overflow: hidden;
list-style: none;
margin: 0;
padding: 0;
background-position: left top;
}
.ajaxful-rating li {
display: inline;
}
.ajaxful-rating a,
.ajaxful-rating span,
.ajaxful-rating .show-value {
position: absolute;
top: 0;
left: 0;
text-indent: -1000em;
height: 25px;
line-height: 25px;
outline: none;
overflow: hidden;
border: none;
}
.ajaxful-rating a:hover,
.ajaxful-rating a:active,
.ajaxful-rating a:focus {
background-position: left bottom;
}
/* This section is generated dynamically.
Just add a call to the helper method 'ajaxful_rating_style' within
the head tags in your main layout
.ajaxful-rating .stars-1{
width: 20%;
z-index: 6;
}
.ajaxful-rating .stars-2{
width: 40%;
z-index: 5;
}
.ajaxful-rating .stars-3{
width: 60%;
z-index: 4;
}
.ajaxful-rating .stars-4{
width: 80%;
z-index: 3;
}
.ajaxful-rating .stars-5{
width: 100%;
z-index: 2;
}
*/
.ajaxful-rating .show-value {
z-index: 1;
background-position: left center;
}
/* smaller star */
.ajaxful-rating.small {
/*width: 50px; this is setted dynamically */
height: 10px;
}
.ajaxful-rating.small,
.ajaxful-rating.small a:hover,
.ajaxful-rating.small a:active,
.ajaxful-rating.small a:focus,
.ajaxful-rating.small .show-value {
background-image: url("/assets/ajaxful_rating/star_small.png");
line-height: 10px;
height: 10px;
}

View File

@ -1,191 +0,0 @@
/*
*= require_tree .
*= require jquery.plupload.queue
*= require bootstrap_and_overrides
*= require fancybox/jquery.fancybox
*= require fancybox/helpers/jquery.fancybox-buttons
*= require fancybox/helpers/jquery.fancybox-thumbs
*= require_self
*/
* {
text-shadow: 1px 1px 1px #999;
/*text-shadow: 0 1px 0 rgba(255, 255, 255, 0.1), 0 0 30px rgba(255, 255, 255, 0.125);*/
font-family: 'Nunito', 'Istok Web', sans-serif;
color: #333;
}
body {
padding-top: 90px;
padding-bottom: 40px;
}
h1, h2, h3, h4, h5, h6 {
color: #666;
}
.navbar-inner {
background-color: #FAFAFA !important;
background-image: -moz-linear-gradient(center top, #FAFAFA, #EAEAEA) !important;
background-image: -ms-linear-gradient(center top, #FAFAFA, #EAEAEA) !important;
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#FAFAFA), to(#EAEAEA)) !important;
background-image: -webkit-linear-gradient(center top, #FAFAFA, #EAEAEA) !important;
background-image: -o-linear-gradient(center top, #FAFAFA, #EAEAEA) !important;
background-image: linear-gradient(top, #FAFAFA, #EAEAEA) !important;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#FAFAFA', endColorstr = '#EAEAEA', GradientType = 0) !important;
}
.navbar .brand {
color: #000 !important;
font-weight: bold !important;
padding-bottom: 5px !important;
padding: 10px 20px 12px;
/*text-shadow: 0 1px 0 rgba(255, 255, 255, 0.1), 0 0 30px rgba(255, 255, 255, 0.125);*/
}
.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret {
border-top-color: #000000;
}
.navbar .nav {
margin-top: 5px;
margin-bottom: 10px;
}
.navbar .nav > li {
padding-right: 5px;
}
.navbar .nav .divider-vertical {
padding: 0;
}
.navbar .nav > li > a {
color: #333333;
font-size: 18px;
}
.navbar .nav > li > a:hover {
background-color: #FAFAFA;
color: #7B7B7B;
border: 0px solid #C9C9C9;
border-radius: 5px 5px 5px 5px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5), 0 1px 0px rgba(255, 255, 255, 0.75);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5), 0 1px 0px rgba(255, 255, 255, 0.75);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5), 0 1px 0px rgba(255, 255, 255, 0.75);
transition: none;
}
.navbar .nav .active > a, .navbar .nav .active > a:hover {
background-color: #FAFAFA;
color: #7B7B7B;
border: 0;
border-radius: 5px 5px 5px 5px;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5), 0 1px 0px rgba(255, 255, 255, 0.75);
transition: none;
}
.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle {
background-color: #FAFAFA;
color: #7B7B7B;
}
.navbar .nav .active > .dropdown-toggle:hover {
color: #7B7B7B;
}
.navbar-search {
margin-top: 15px;
}
.navbar-search .search-query {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 15px;
font-weight: normal;
line-height: 1.2;
color: #333;
background: #666;
background: rgba(255, 255, 255, 0.3);
border: 0;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5), 0 1px 0px rgba(255, 255, 255, 0.75);
transition: none;
}
.navbar-search .search-query :-moz-placeholder {
color: #666;
}
.navbar-search .search-query::-webkit-input-placeholder {
color: #666;
}
.navbar-search .search-query:hover {
color: #333;
background-color: #999999;
background-color: rgba(255, 255, 255, 0.5);
}
.navbar-search .search-query:focus, .navbar-search .search-query.focused {
padding: 5px 10px;
color: #333333;
text-shadow: 0 1px 0 #ffffff;
background-color: #ffffff;
border: 0;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
outline: 0;
}
.ajaxful-rating-wrapper {
float: right;
}
.view-btn {
display: inline;
padding: 5px;
float: left;
}
.anythingSlider {
padding: 0 0 28px 0;
}
.thumbnail {
background: none repeat scroll 0 0 #FFFFFF;
border: 0 none;
border-radius: 7px 7px 7px 7px;
box-shadow: 1px 1px 3px #D9D9D9;
display: block;
height: 340px;
}
.caption {
position: relative;
bottom: 0px;
height: 150px;
}
.caption .title {
padding: 5px 0 5px 0;
font-size: 13px;
text-align: center;
}
.caption .descr {
display: block;
padding: 10px 0 0 0;
}
.caption .controls {
position: absolute;
bottom: 5px;
width: 250px;
}
.caption .controls .tooltips{
float: left;
width: 15px;
padding: 5px;
}
.icon-popover{
cursor: pointer;
}

View File

@ -1,32 +0,0 @@
@import "twitter/bootstrap/bootstrap";
body {
padding-top: 60px;
}
@import "twitter/bootstrap/responsive";
// Set the correct sprite paths
@iconSpritePath: asset-path('twitter/bootstrap/glyphicons-halflings.png');
@iconWhiteSpritePath: asset-path('twitter/bootstrap/glyphicons-halflings-white.png');
// Set the Font Awesome (Font Awesome is default. You can disable by commenting below lines)
// Note: If you use asset_path() here, your compiled boostrap_and_overrides.css will not
// have the proper paths. So for now we use the absolute path.
@fontAwesomeEotPath: '/assets/fontawesome-webfont.eot';
@fontAwesomeWoffPath: '/assets/fontawesome-webfont.woff';
@fontAwesomeTtfPath: '/assets/fontawesome-webfont.ttf';
@fontAwesomeSvgPath: '/assets/fontawesome-webfont.svg';
// Font Awesome
@import "fontawesome";
// Your custom LESS stylesheets goes here
//
// Since bootstrap was imported above you have access to its mixins which
// you may use and inherit here
//
// If you'd like to override bootstrap's own variables, you can do so here as well
// See http://twitter.github.com/bootstrap/less.html for their names and documentation
//
// Example:
// @linkColor: #ff0000;

View File

@ -1,3 +0,0 @@
// Place all the styles related to the home controller here.
// They will automatically be included in application.css.
// You can use Less here: http://lesscss.org/

View File

@ -1,177 +0,0 @@
/*
Plupload
------------------------------------------------------------------- */
.plupload_button {
display: -moz-inline-box; /* FF < 3*/
display: inline-block;
font: normal 12px sans-serif;
text-decoration: none;
color: #42454a;
border: 1px solid #bababa;
padding: 2px 8px 3px 20px;
margin-right: 4px;
background: #f3f3f3 url(asset_path("buttons.png")) no-repeat 0 center;
outline: 0;
/* Optional rounded corners for browsers that support it */
-moz-border-radius: 3px;
-khtml-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
.plupload_button:hover {
color: #000;
text-decoration: none;
}
.plupload_disabled, a.plupload_disabled:hover {
color: #737373;
border-color: #c5c5c5;
background: #ededed url(asset_path('buttons-disabled.png')) no-repeat 0 center;
cursor: default;
}
.plupload_add {
background-position: -181px center;
}
.plupload_wrapper {
font: normal 11px Verdana,sans-serif;
width: 100%;
}
.plupload_container {
padding: 8px;
background: url(asset_path('transp50.png'));
/*-moz-border-radius: 5px;*/
}
.plupload_container input {
border: 1px solid #DDD;
font: normal 11px Verdana,sans-serif;
width: 98%;
}
.plupload_header {background: #2A2C2E url(asset_path('backgrounds.gif')) repeat-x;}
.plupload_header_content {
background: url(asset_path('backgrounds.gif')) no-repeat 0 -317px;
min-height: 56px;
padding-left: 60px;
color: #FFF;
}
.plupload_header_title {
font: normal 18px sans-serif;
padding: 6px 0 3px;
}
.plupload_header_text {
font: normal 12px sans-serif;
}
.plupload_filelist {
margin: 0;
padding: 0;
list-style: none;
}
.plupload_scroll .plupload_filelist {
height: 185px;
background: #F5F5F5;
overflow-y: scroll;
}
.plupload_filelist li {
padding: 10px 8px;
background: #F5F5F5 url(asset_path('backgrounds.gif')) repeat-x 0 -156px;
border-bottom: 1px solid #DDD;
}
.plupload_filelist_header, .plupload_filelist_footer {
background: #DFDFDF;
padding: 8px 8px;
color: #42454A;
}
.plupload_filelist_header {
border-top: 1px solid #EEE;
border-bottom: 1px solid #CDCDCD;
}
.plupload_filelist_footer {border-top: 1px solid #FFF; height: 22px; line-height: 20px; vertical-align: middle;}
.plupload_file_name {float: left; overflow: hidden}
.plupload_file_status {color: #777;}
.plupload_file_status span {color: #42454A;}
.plupload_file_size, .plupload_file_status, .plupload_progress {
float: right;
width: 80px;
}
.plupload_file_size, .plupload_file_status, .plupload_file_action {text-align: right;}
.plupload_filelist .plupload_file_name {width: 205px}
.plupload_file_action {
float: right;
width: 16px;
height: 16px;
margin-left: 15px;
}
.plupload_file_action * {
display: none;
width: 16px;
height: 16px;
}
li.plupload_uploading {background: #ECF3DC url(asset_path('backgrounds.gif')) repeat-x 0 -238px;}
li.plupload_done {color:#AAA}
li.plupload_delete a {
background: url(asset_path('delete.gif'));
}
li.plupload_failed a {
background: url(asset_path('error.gif'));
cursor: default;
}
li.plupload_done a {
background: url(asset_path('done.gif'));
cursor: default;
}
.plupload_progress, .plupload_upload_status {
display: none;
}
.plupload_progress_container {
margin-top: 3px;
border: 1px solid #CCC;
background: #FFF;
padding: 1px;
}
.plupload_progress_bar {
width: 0px;
height: 7px;
background: #CDEB8B;
}
.plupload_scroll .plupload_filelist_header .plupload_file_action, .plupload_scroll .plupload_filelist_footer .plupload_file_action {
margin-right: 17px;
}
/* Floats */
.plupload_clear,.plupload_clearer {clear: both;}
.plupload_clearer, .plupload_progress_bar {
display: block;
font-size: 0;
line-height: 0;
}
li.plupload_droptext {
background: transparent;
text-align: center;
vertical-align: middle;
border: 0;
line-height: 165px;
}

View File

@ -1,146 +0,0 @@
/*
Plupload
------------------------------------------------------------------- */
.plupload_button {cursor: pointer;}
.plupload_wrapper {
font: normal 11px Verdana,sans-serif;
width: 100%;
}
.plupload .plupload_container input {width: 98%;}
.plupload .plupload_filelist_footer {border-width: 1px 0 0 0}
.plupload .plupload_filelist_header {border-width: 0 0 1px 0}
div.plupload .plupload_file {border-width: 0 0 1px 0}
div.plupload div.plupload_header {border-width: 0 0 1px 0; position: relative;}
.plupload_file .ui-icon {
cursor:pointer;
}
.plupload_header_content {
background-image: url(asset_path('plupload.png'));
background-repeat: no-repeat;
background-position: 8px center;
min-height: 56px;
padding-left: 60px;
position:relative;
}
.plupload_header_content_bw {background-image: url(asset_path('plupload-bw.png'));}
.plupload_header_title {
font: normal 18px sans-serif;
padding: 6px 0 3px;
}
.plupload_header_text {font: normal 12px sans-serif;}
.plupload_filelist,
.plupload_filelist_content {
border-collapse: collapse;
margin: 0;
padding: 0;
width: 100%;
-moz-user-select:none;
-webkit-user-select:none;
user-select:none;
}
.plupload_cell {padding: 8px 6px;}
.plupload_file {
border-left: none;
border-right: none;
}
.plupload .ui-sortable-helper,
.plupload .ui-sortable .plupload_file {
cursor:move;
}
.plupload_scroll {
max-height: 180px;
min-height: 168px;
_height: 168px;
}
.plupload_file_size, .plupload_file_status {text-align: right;}
.plupload_file_size, .plupload_file_status {width: 52px;}
.plupload_file_action {width: 16px;}
.plupload_file_name {
overflow: hidden;
padding-left: 10px;
}
.plupload_file_rename {
width:95%;
}
.plupload_progress {width: 60px;}
.plupload_progress_container {padding: 1px;}
/* Floats */
.plupload_right {float: right;}
.plupload_left {float: left;}
.plupload_clear,.plupload_clearer {clear: both;}
.plupload_clearer, .plupload_progress_bar {
display: block;
font-size: 0;
line-height: 0;
}
.plupload_clearer {height: 0;}
/* Misc */
.plupload_hidden {display: none;}
.plupload_droptext {
background: transparent;
text-align: center;
vertical-align: middle;
border: 0;
line-height: 165px;
}
.plupload_buttons, .plupload_upload_status {float: left}
.plupload_message {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
width: 100%;
}
.plupload_message p {
padding:0.7em;
margin:0;
}
.plupload_message strong {
font-weight: bold;
}
plupload_message i {
font-style: italic;
}
.plupload_message p span.ui-icon {
float: left;
margin-right: 0.3em;
}
.plupload_header_content .ui-state-error,
.plupload_header_content .ui-state-highlight {
border:none;
}
.plupload_message_close {
position:absolute;
top:5px;
right:5px;
cursor:pointer;
}
.plupload .ui-sortable-placeholder {
height:35px;
}

View File

@ -1,115 +0,0 @@
class AlbumsController < ApplicationController
before_filter :check_public_access
skip_before_filter :authenticate_user!, :only => [:index, :show]
def index
add_breadcrumb t('activerecord.models.album.popular'), collections_path, :title => t('activerecord.models.album.popular')
add_breadcrumb t('activerecord.actions.create', :model => I18n.t('activerecord.models.album.single')), new_album_path,
:title => t('activerecord.actions.create', :model => I18n.t('activerecord.models.album.single')),
:li_icon => 'icon-plus-sign'
if params[:tag_id]
@albums = Album.where(:conditions => [ "id IN ( SELECT DISTINCT photos.album_id FROM photos WHERE photos.id IN ( SELECT photo_id FROM photo_tags WHERE photo_tags.tag_id = :q) )", { :q => Tag.find( params[:tag_id] ).id } ]).order('title')
elsif params[:q]
#search = params[:q]
#search = search.split("AND").map{|q|q.strip}
#@albums = Album.find(:all, :select => 'DISTINCT albums.id, albums.title', :limit => 20, :conditions => { :tags => {:title => search}}, :joins => 'LEFT OUTER JOIN photos ON albums.id = photos.album_id LEFT OUTER JOIN photo_tags ON photos.id = photo_tags.photo_id LEFT OUTER JOIN tags ON photo_tags.tag_id = tags.id', :order => "albums.title ASC" )
#@albums = Album.find(:all, :select => 'DISTINCT album_id', :conditions => [ "title LIKE :q OR description LIKE :q OR id IN ( SELECT DISTINCT photos.album_id FROM photos WHERE photos.description LIKE :q OR photos.title LIKE :q OR photos.id IN ( SELECT photo_id FROM photo_tags LEFT OUTER JOIN tags ON photo_tags.tag_id = tags.id WHERE tags.title LIKE :q) )", { :q => '%' + params[:q] + '%' } ], :order => 'title')
params[:q].split(" AND ").each {|q|
qphotos = Photo.find(:all, :select => 'DISTINCT album_id', :conditions => [ "description LIKE :q OR title LIKE :q OR id IN ( SELECT photo_id FROM photo_tags LEFT OUTER JOIN tags ON photo_tags.tag_id = tags.id WHERE tags.title LIKE :q)", { :q => '%' + q + '%' } ])
qalbums = Album.find(:all, :conditions => ['title LIKE :q OR description LIKE :q OR id IN (:ids)', { :ids => qphotos.map{|p|p.album_id}, :q => '%' + q + '%' }], :order => 'title' )
if @albums
@albums = @albums & qalbums
else
@albums = qalbums
end
}
else
@albums = Album.popular.page(@page).per(@per_page)
end
respond_to do |format|
format.html
format.json { render :json => @albums }
format.xml { render :xml => @albums }
end
end
def untouched
@albums = Album.untouched()
respond_to do |format|
format.html
format.json { render :json => @albums }
format.xml { render :xml => @albums }
end
end
def show
@album = Album.find( params[:id])
@photos = @album.photos.popular
respond_to do |format|
format.html
format.json { render :json => @album }
format.xml { render :xml => @album }
format.pdf { render :pdf => @album.title }
end
end
def new
@album = Album.new
end
def create
@album = Album.new(params[:album])
if @album.save
flash[:notice] = "Album created! Now add some nice photos."
if params[:collection_id]
@album.collections << Collection.find( params[:collection_id] )
redirect_to upload_collection_album_photos_path(params[:collection_id], @album )
else
redirect_to upload_album_photos_path( @album )
end
else
render :action => :new
end
end
def edit
@album = Album.find( params[:id])
end
def update
@album = Album.find( params[:id])
if @album.update_attributes(params[:album])
flash[:notice] = "Album updated!"
if params[:collection_id]
redirect_to collection_album_path(params[:collection_id], @album )
else
redirect_to @album
end
else
render :action => :edit
end
end
def destroy
@album = Album.find( params[:id])
if @album.destroy
if params[:collection_id]
redirect_to collection_path(params[:collection_id] )
else
redirect_to albums_path
end
else
redirect_to @album
end
end
def rate
@album = Album.find(params[:id])
@album.rate(params[:stars], current_user, params[:dimension])
render :json => {:id => @album.wrapper_dom_id(params), :width => 125}
end
end

View File

@ -1,51 +0,0 @@
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
layout 'bootstrap'
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details
before_filter :set_locale
before_filter :authenticate_user!, :set_current_user
before_filter :setup, :set_pagination_params
private
# This hack is needed to access the current user in models. See http://rails-bestpractices.com/posts/47-fetch-current-user-in-models
def set_current_user
User.current = current_user
end
def setup
redirect_to new_account_path if User.all.size == 0
end
def check_public_access
require_user if ENV['PRIVATE'] == 'true'
end
def store_location
session[:return_to] = request.fullpath
end
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
private
def set_pagination_params
@page = params[:page]
@per_page = params[:per_page]
end
def set_locale
I18n.locale = session[:locale]
if params[:locale] && I18n.available_locales.include?(params[:locale].to_sym)
session[:locale] = I18n.locale = params[:locale].to_sym
end
end
end

View File

@ -1,86 +0,0 @@
class CollectionsController < ApplicationController
before_filter :check_public_access
skip_before_filter :authenticate_user!, :only => [:index, :show]
add_breadcrumb I18n.t('home_page'), :root_path, :title => I18n.t('home_page')
def index
add_breadcrumb t('activerecord.models.collection.popular'), collections_path, :title => t('activerecord.models.collection.popular')
add_breadcrumb t('activerecord.actions.create', :model => I18n.t('activerecord.models.collection.single')), new_collection_path,
:title => t('activerecord.actions.create'), :li_icon => 'icon-plus-sign'
@collections = Collection.popular.page(@page).per(@per_page)
respond_to do |format|
format.html
format.json { render :json => @collections }
format.xml { render :xml => @collections }
end
end
def show
@collection = Collection.find( params[:id] )
add_breadcrumb t('activerecord.models.collection.popular'), collections_path, :title => t('activerecord.models.collection.popular')
add_breadcrumb @collection.title, collection_path(@collection), :title => @collection.title
add_breadcrumb t('activerecord.actions.update', :model => I18n.t('activerecord.models.collection.single')), edit_collection_path,
:title => t('activerecord.actions.update', :model => I18n.t('activerecord.models.collection.single'))
add_breadcrumb t('activerecord.actions.destroy', :model => I18n.t('activerecord.models.collection.single')),collection_path(@collection),
:title => t('activerecord.actions.destroy', :model => I18n.t('activerecord.models.collection.single'))
@albums = @collection.albums.includes(:photos).where("photos.id NOT NULL").order('albums.rating_average desc').page(@page).per(@per_page)
respond_to do |format|
format.html
format.json { render :json => @collection }
format.xml { render :xml => @collection }
format.pdf { render :pdf => @collection.title }
end
end
def new
@collection = Collection.new
add_breadcrumb t('activerecord.models.collection.other').mb_chars.capitalize.to_s, collections_path,
:title => t('activerecord.models.collection.other')
add_breadcrumb t('activerecord.actions.new', :model => I18n.t('activerecord.models.collection.one')), new_collection_path,
:title => t('activerecord.actions.new', :model => I18n.t('activerecord.models.collection.one'))
end
def create
@collection = Collection.new(params[:collection])
if @collection.save
flash[:notice] = "Collection created! Now lets add a new album."
redirect_to new_collection_album_path(@collection)
else
render :action => :new
end
end
def edit
@collection = Collection.find( params[:id])
end
def update
@collection = Collection.find( params[:id])
add_breadcrumb t('activerecord.models.collection.popular'), collections_path, :title => t('activerecord.models.collection.popular')
add_breadcrumb t('activerecord.actions.create', :model => I18n.t('activerecord.models.collection.single')), new_collection_path, :title => t('activerecord.actions.create')
if @collection.update_attributes(params[:collection])
flash[:notice] = "Collection updated!"
redirect_to @collection
else
render :action => :edit
end
end
def destroy
@collection = Collection.find( params[:id])
if @collection.destroy
redirect_to collections_path
else
redirect_to @collection
end
end
def rate
@collection = Collection.find(params[:id])
@collection.rate(params[:stars], current_user, params[:dimension])
render :json => {:id => @collection.wrapper_dom_id(params), :width => 125}
end
end

View File

@ -1,16 +0,0 @@
class HomeController < ApplicationController
skip_before_filter :authenticate_user!, :only => [:index]
add_breadcrumb I18n.t(:home_page), :root_path
def index
@collections = Collection.popular.limit(12)
@popular_photos = Photo.popular.limit(10)
respond_to do |format|
format.html
format.json { render :json => @collections }
format.xml { render :xml => @collections }
end
end
end

View File

@ -1,16 +0,0 @@
class LocaleController < ApplicationController
skip_before_filter :authenticate_user!, :only => [:set]
def set
if request.referer && request.referer.starts_with?('http://' + request.host)
session['return_to'] = request.referer
end
if params[:locale] && I18n.available_locales.include?(params[:locale].to_sym)
session[:locale] = I18n.locale = params[:locale].to_sym
flash.notice = t(:locale_changed)
else
flash[:error] = t(:locale_not_changed)
end
redirect_back_or_default(root_path)
end
end

View File

@ -1,157 +0,0 @@
class PhotosController < ApplicationController
before_filter :check_public_access
skip_before_filter :authenticate_user!, :only => [:index, :show]
def index
if params[:tag_id] && params[:album_id]
@tag = Tag.find_by_title!( params[:tag_id] )
@photos = @tag.photos.where(:conditions => ['photos.album_id = :album', {:album => Album.find(params[:album_id] ) } ]).order("photos.id ASC")
elsif params[:tag_id]
@tag = Tag.find_by_title!( params[:tag_id] )
@photos = @tag.photos.order("photos.id ASC")
elsif params[:album_id]
@album = Album.find( params[:album_id])
@photos = @album.photos.order("photos.id ASC")
elsif params[:q]
#search = params[:q]
#search = search.split("AND").map{|q|q.strip}
#@photos = Photo.find(:all, :select => 'DISTINCT photos.id, photos.album_id, photos.title, photos.path', :limit => 20, :conditions => { :tags => {:title => search}}, :joins => 'LEFT OUTER JOIN photo_tags ON photos.id = photo_tags.photo_id LEFT OUTER JOIN tags ON photo_tags.tag_id = tags.id', :include => [:album], :order => "photos.title ASC" )
params[:q].split(" AND ").each {|q|
qphotos = Photo.find(:all, :limit => 20, :conditions => [ "photos.description LIKE :q OR photos.title LIKE :q OR photos.id IN ( SELECT photo_id FROM photo_tags LEFT OUTER JOIN tags ON photo_tags.tag_id = tags.id WHERE tags.title = :t) ", { :q => '%' + q + '%', :t => q } ], :include => :album, :order => "photos.id ASC" )
if @photos
@photos = @photos & qphotos
else
@photos = qphotos
end
}
else
@photos = Photo.popular.page(@page).per(@per_page)
end
respond_to do |format|
format.html
format.json { render :json => @photos }
format.xml { render :xml => @photos }
end
end
def untouched
if params[:album_id]
@album = Album.find( params[:album_id])
@photos = @album.photos.untouched.page(@page).per(@per_page)
else
@photos = Photo.untouched().page(@page).per(@per_page)
end
respond_to do |format|
format.html
format.json { render :json => @photos }
format.xml { render :xml => @photos }
end
end
def show
@photo = Photo.find( params[:id] )
previous_rs = Photo.previous( @photo.id, @photo.album )
@previous = previous_rs.first unless previous_rs.empty?
next_rs = Photo.next( @photo.id, @photo.album )
@next = next_rs.first unless next_rs.empty?
respond_to do |format|
format.html
format.json { render :json => @photo }
format.xml { render :xml => @photo }
end
end
def scan
require "scan"
ScanFiles.Scan(false)
redirect_to(root_path)
end
def new
@photo = Photo.new
end
def upload
@album = Album.find( params[:album_id])
end
def create
@photo = Photo.new(params[:photo])
@photo.attachment = params[:file]
respond_to do |format|
if @photo.save
format.html { render :text => "FILEID:" + @photo.attachment.album.url }
format.xml { render :nothing => true }
else
format.html { render :text => "ERRORS:" + @photo.errors.full_messages.join(" "), :status => 500 }
format.xml { render :xml => @photo.errors, :status => 500 }
end
end
end
def edit
@photo = Photo.find( params[:id])
@tags = Tag.all.map { |tag| tag.title }.join('\',\'')
end
def edit_multiple
if params[:album_id]
@album = Album.find( params[:album_id] )
@photos = @album.photos
else
@photos = Photo.find( params[:photo_ids] )
end
end
def update
@photo = Photo.find( params[:id])
if @photo.update_attributes(params[:photo])
flash[:notice] = "Photo updated!"
if params[:collection_id]
redirect_to collection_album_photo_path( params[:collection_id], params[:album_id], @photo )
elsif params[:album_id]
redirect_to album_photo_path( params[:album_id], @photo )
else
redirect_to @photo
end
else
render :action => :edit
end
end
def update_multiple
@photos = params[:photos][:photo]
@photos.each do |photo_item|
photo = Photo.find( photo_item[0] )
if photo_item[1][:_delete] == "1"
photo.destroy
else
photo.title = photo_item[1][:title]
photo.tag_list = photo_item[1][:tags]
photo.save
end
end
flash[:notice] = "Updated photos!"
redirect_to photos_path
end
def destroy
@photo = Photo.find( params[:id])
@album = @photo.album
if @photo.destroy
if params[:collection_id]
redirect_to collection_album_path( params[:collection_id], @album )
else
redirect_to @album
end
else
redirect_to @photo
end
end
def rate
@photo = Photo.find(params[:id])
@photo.rate(params[:stars], current_user, params[:dimension])
render :json => {:id => @photo.wrapper_dom_id(params), :width => 125}
end
end

View File

@ -1,16 +0,0 @@
class TagsController < ApplicationController
before_filter :check_public_access
def index
if params[:album_id]
@tags = Album.find( params[:album_id] ).photo_tags
else
@tags = Tag.order('title')
end
respond_to do |format|
format.html
format.json { render :json => @tags }
format.xml { render :xml => @tags }
end
end
end

View File

@ -1,49 +0,0 @@
class UsersController < ApplicationController
before_filter :check_public_access
skip_before_filter :authenticate_user!, :only => [:new, :create]
skip_filter :setup
def new
@user = User.new
end
def create
@user = User.new(params[:user])
if @user.save
if User.all.length == 1
@user.roles << Role.create(:name => 'admin')
end
flash[:notice] = "Account registered!"
redirect_back_or_default new_collection_path
else
render :action => :new
end
end
def show
@user = @current_user
end
def edit
@user = @current_user
end
def update
@user = @current_user # makes our views "cleaner" and more consistent
if @user.update_attributes(params[:user])
flash[:notice] = "Account updated!"
redirect_to account_path
else
render :action => :edit
end
end
def destroy
@user = @current_user
if @user.destroy
redirect_to users_path
else
redirect_to @user
end
end
end

View File

@ -1,10 +0,0 @@
module AlbumsHelper
def new_upload_path_with_session_information
session_key = self.get_session_key
photos_path(session_key => cookies[session_key], request_forgery_protection_token => form_authenticity_token)
end
def get_session_key
Rails.application.config.session_options[:key]
end
end

View File

@ -1,34 +0,0 @@
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
=begin
def breadcrumbs(sep = "/", include_home = true)
levels = request.path.split('?')[0].split('/')
levels.delete_at(0)
#links = "You are here: "
links = content_tag('li', (content_tag('a', t(:home_page), :href => root_path ) if include_home))
nocrumb = ["collections", "albums", "photos", "tags", "new", "edit", "tags"]
levels.each_with_index do |level, index|
level = level.gsub(/^[0-9]+\-/,"") #if levels[index-1] == "photos"
level = level.gsub("-", " ")
if index+1 == levels.length
#links += " #{sep} #{level.upcase}" unless nocrumb.include?(level)
#elsif !nocrumb.include?(level)
links += " " + sep + " "
links += content_tag('li', content_tag('a', level, :href => '/'+levels[0..index].join('/')))
end
end
content_tag("ul", links, :class => "breadcrumb")
end
=end
def pluralize(string, count=nil, variants=nil)
# example variants for russian: # Russian.pluralize(3.14, "вещь", "вещи", "вещей", "вещи")
a,b,c,d=*variants
I18n.locale.eql?(:ru) ? Russian.pluralize(count, a,b,c,d) : string.pluralize
end
end

View File

@ -1,2 +0,0 @@
module HomeHelper
end

View File

@ -1,3 +0,0 @@
module UsersHelper
end

View File

@ -1,18 +0,0 @@
require 'rack/utils'
class FlashSessionCookieMiddleware
def initialize(app, session_key = '_session_id')
@app = app
@session_key = session_key
end
def call(env)
if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
req = Rack::Request.new(env)
env['HTTP_COOKIE'] = [ @session_key,
req.params[@session_key] ].join('=').freeze unless req.params[@session_key].nil?
env['HTTP_ACCEPT'] = "#{req.params['_http_accept']}".freeze unless req.params['_http_accept'].nil?
end
@app.call(env)
end
end

View File

@ -1,63 +0,0 @@
class Ability
include CanCan::Ability
def initialize(user)
self.clear_aliased_actions
alias_action :edit, :to => :update
alias_action :new, :to => :create
alias_action :new_action, :to => :create
alias_action :show, :to => :read
if user.has_role? 'admin'
can :manage, :all
else
#############################
can :read, User do |resource|
resource == user
end
can :update, User do |resource|
resource == user
end
can :create, User
##############################
can :read, Profile do |resource|
resource == user
end
can :update, Profile do |resource|
resource == user
end
can :create, Profile
###############################
can :read, Link do |resource|
resource == user
end
can :update, Link do |resource|
resource == user
end
can :create, Link
end
# Define abilities for the passed in user here. For example:
#
# user ||= User.new # guest user (not logged in)
# if user.admin?
# can :manage, :all
# else
# can :read, :all
# end
#
# The first argument to `can` is the action you are giving the user permission to do.
# If you pass :manage it will apply to every action. Other common actions here are
# :read, :create, :update and :destroy.
#
# The second argument is the resource the user can perform the action on. If you pass
# :all it will apply to every resource. Otherwise pass a Ruby class of the resource.
#
# The third argument is an optional hash of conditions to further filter the objects.
# For example, here the user can only update published articles.
#
# can :update, Article, :published => true
#
# See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
end
end

View File

@ -1,107 +0,0 @@
class Album < ActiveRecord::Base
extend Ext::GroupFor
ajaxful_rateable :stars => 5, :cache_column => :rating_average
has_many :photos, :dependent => :destroy
has_many :collection_albums
has_many :collections, :through => :collection_albums
validates :path, :presence => true, :uniqueness => true #, :message => "Album already exsists on disc"
validates :title, :presence => true #, :message => "can't be blank"
before_validation :ensure_path, :set_title
after_create :create_folders
after_destroy :destroy_folders
attr_accessor :tags
scope :visible, lambda { where(:public => true) }
scope :popular, lambda{visible.includes(:photos).where("photos.id NOT NULL").order('albums.rating_average desc')}
scope :untouched, lambda{where("albums.id IN ( SELECT DISTINCT photos.album_id FROM photos WHERE photos.description IS NULL AND photos.id NOT IN ( SELECT photo_id FROM photo_tags) )").order('title')}
scope :unused, lambda{where("albums.id NOT IN (SELECT album_id FROM collection_albums)")}
scope :used, lambda{where("albums.id IN (SELECT album_id FROM collection_albums)")}
def to_param
"#{id}-#{title.parameterize}"
end
def ensure_path
self.path = self.title.parameterize unless self.path
end
def set_title
self.title = File.basename(self.path).titleize unless self.title || !self.path
end
def tags
# should maybe cache this to database?
# should maybe return array instead?
tags = Array.new
self.photos.map { |photo|
if photo.tags.empty?
# photo has no tags => no unversial tags for this album
return
else
photo.tags
end
}.each_with_index { |photo_tags, i|
# returns tag collection for each photo
if i == 0
tags = photo_tags
else
# combine arrays if they have identical tags.
# Will remove tags that are only tagged to one photo
#tags = tags & photo_tags
tags = tags & photo_tags
end
}
return tags
end
def tags=(tags)
tags = tags.split(" ").sort
current_tags = (self.tags.nil? ? [] : self.tags.map { |tag| tag.title })
return if tags == self.tags
# find tags that should be removed from this album - thus remove from all photos in album
# i.e. tags listed in self.tag_list but no in parameter tags
#current_tags.map {|tag|tag if !tags.include?(tag) }.compact
(current_tags - tags).each { |tag|
self.photos.each { |photo|
photo.untag(tag)
}
}
# add universial tags to all photos in album
(tags - current_tags).each do |tag|
self.photos.each { |photo|
photo.tag(tag)
}
end
end
def photo_tags
tags = Array.new
self.photos.each { |photo|
tags = tags | photo.tags
}
return tags
end
protected
private
def create_folders
#Dir.mkdir( APP_CONFIG[:photos_path] + self.path ) unless File.exists?( APP_CONFIG[:photos_path] + self.path )
#Dir.mkdir( APP_CONFIG[:thumbs_path] + self.path ) unless File.exists?( APP_CONFIG[:thumbs_path] + self.path )
end
def destroy_folders
#puts "DELETE DIRECTORY " + APP_CONFIG[:photos_path] + self.path
#Dir.delete( APP_CONFIG[:photos_path] + self.path ) if File.exists?( APP_CONFIG[:photos_path] + self.path )
#Dir.delete( APP_CONFIG[:thumbs_path] + self.path ) if File.exists?( APP_CONFIG[:thumbs_path] + self.path )
end
end

View File

@ -1,27 +0,0 @@
class Collection < ActiveRecord::Base
extend Ext::GroupFor
ajaxful_rateable :stars => 5, :cache_column => :rating_average
has_many :collection_albums
has_many :albums, :through => :collection_albums
attr_accessor :album_list
validates :title, :presence => true
scope :visible, where(:public => true)
scope :popular, lambda{visible.includes(:albums => :photos).where("photos.id NOT NULL").order('collections.rating_average desc')}
def photos_count
self.albums.includes(:photos).size
end
def to_param
"#{id}-#{title.parameterize}"
end
def album_list=(albums)
self.albums = Album.find(albums.map{|album|album[0]})
end
end

View File

@ -1,4 +0,0 @@
class CollectionAlbum < ActiveRecord::Base
belongs_to :album
belongs_to :collection
end

View File

@ -1,90 +0,0 @@
class Photo < ActiveRecord::Base
extend Ext::GroupFor
ajaxful_rateable :stars => 5, :cache_column => :rating_average
belongs_to :album
has_many :photo_tags, :dependent => :destroy
has_many :tags, :through => :photo_tags
mount_uploader :attachment, FileUploader
before_create :exif_read
before_update :exif_write
after_create :set_title, :set_visible
attr_accessor :tag_list
scope :visible, where(:public => true)
scope :popular, visible.order('rating_average desc')
scope :untouched, :conditions => "photos.description IS NULL AND photos.id NOT IN ( SELECT photo_id FROM photo_tags)", :include => :album
scope :previous, lambda { |p,a| { :conditions => ["id < :id AND album_Id = :album ", { :id => p, :album => a } ], :limit => 1, :order => "id DESC"} }
scope :next, lambda { |p,a| { :conditions => ["id > :id AND album_Id = :album ", { :id => p, :album => a } ], :limit => 1, :order => "id ASC"} }
def to_param
"#{id}-#{title.parameterize}"
end
def tag(title)
return if self.tags.collect{|tag|tag.title}.include?( title )
self.photo_tags.create(:tag => Tag.find_or_create_by_title( :title => title) )
self.reload
end
def untag(title)
return if !self.tags.collect{|tag|tag.title}.include?( title )
# perhaps not the best way but it finds the correct PhotoTag and deletes it
self.photo_tags.select{|photo_tag|
photo_tag.tag.title == title
}.each {|photo_tag|photo_tag.destroy}
self.reload
end
def tag_list
return self.tags.order('title').map{ |t| t.title }.sort.join(" ")
end
def tag_list=(tags)
ts = Array.new
tags.split(" ").each do |tag|
ts.push( Tag.find_or_create_by_title( :title => tag.downcase) )
end
self.tags = ts
end
def _delete
0
end
private
def set_visible
update_attribute(:public, true) unless self.public
end
def set_title
update_attribute(:title, self.attachment.file.basename.titleize) unless self.title
end
def exif_read
photo = MiniExiftool.new(self.attachment.file.file)
self.longitude = photo.GPSLongitude if self.longitude.nil?
self.latitude = photo.GPSLatitude if self.latitude.nil?
self.title = photo.DocumentName if self.title.nil?
self.description = photo.ImageDescription if self.description.nil? && photo.ImageDescription != 'Exif_JPEG_PICTURE'
self.tag_list = (self.tags.empty? ? "" : self.album.tag_list) + " " + (photo.Keywords.nil? ? "" : photo.Keywords.to_a.map { |tag| tag.gsub(" ", "_") }.join(" "))
end
def exif_write
# should only write if tags are changed as images can be large and thus ExifTool will take a while to write to the file
photo = MiniExiftool.new(self.attachment.file.file)
photo.GPSLongitude = self.longitude
photo.GPSLatitude = self.latitude
photo.DocumentName = self.title
photo.ImageDescription = self.description
photo.Keywords = self.tags
photo.save
end
end

View File

@ -1,4 +0,0 @@
class PhotoTag < ActiveRecord::Base
belongs_to :tag
belongs_to :photo
end

View File

@ -1,7 +0,0 @@
class Rate < ActiveRecord::Base
belongs_to :rater, :class_name => "User"
belongs_to :rateable, :polymorphic => true
validates_numericality_of :stars, :minimum => 1
attr_accessible :rate, :dimension
end

View File

@ -1,5 +0,0 @@
class Role < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :users
end

View File

@ -1,7 +0,0 @@
class SecretLinkObserver < ActiveRecord::Observer
observe :collection, :album, :photo
def before_create(record)
record.url = ::SecureRandom.hex(16)
end
end

View File

@ -1,23 +0,0 @@
class Tag < ActiveRecord::Base
has_many :photo_tags, :dependent => :destroy
has_many :photos, :through => :photo_tags
validates_uniqueness_of :title
before_validation :downcase_title
def self.tag_list
return self.find(:all).map { |tag| tag.title }.join('\',\'')
end
def to_param
title.parameterize
end
protected
def downcase_title
self.title.downcase! if attribute_present?("title")
end
end

View File

@ -1,45 +0,0 @@
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :confirmable, :token_authenticatable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :lockable
attr_accessible :id, :name, :second_name, :surname, :email, :password, :password_confirmation, :remember_me, :userpic
ajaxful_rater
mount_uploader :userpic, UserpicUploader
has_and_belongs_to_many :roles
def small_url
userpic.url(:small)
end
alias_method :avatar, :small_url
def thumb_url
userpic.url(:thumb)
end
def original_url
userpic.url(:original)
end
##########################################################
# This hack is needed to access the current user in models.
#See http://rails-bestpractices.com/posts/47-fetch-current-user-in-models
def self.current
Thread.current[:user]
end
def self.current=(user)
Thread.current[:user] = user
end
def self.admin_created?
User.admin.count > 0
end
def has_role?(role_in_question)
roles.any? { |role| role.name == role_in_question.to_s }
end
end

View File

@ -1,98 +0,0 @@
# encoding: utf-8
class FileUploader < CarrierWave::Uploader::Base
@@generate_file_name = ''
@@original_filename = ''
# Include RMagick or ImageScience support
# include CarrierWave::RMagick
# include CarrierWave::ImageScience
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader
if ENV['S3_KEY']
storage :fog
def cache_dir
"#{Rails.root.to_s}/tmp/uploads" if ENV['HEROKU'] == 'true'
end
else
storage :file
end
# Override the directory where uploaded files will be stored
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
#{}"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
ENV['STORAGE_PATH'] + "/files/#{model.album.path}/#{model.id}"
end
def filename
unless @@original_filename == original_filename
@@original_filename = original_filename
@@generate_file_name = "#{::SecureRandom.hex(8)}#{File.extname(original_filename).downcase}" if original_filename
end
@@generate_file_name
end
# Provide a default URL as a default if there hasn't been a file uploaded
# def default_url
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded.
# process :scale => [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files
version :thumb do
process :resize_to_fill => [260, 180]
def store_dir
ENV['STORAGE_PATH'] + "/thumbs/#{model.album.path}/#{model.id}"
end
end
######################################################################################################################
# Note
# The default grid system provided in Bootstrap utilizes 12 columns that
# render out at widths of 724px, 940px (default without responsive CSS included), and 1170px.
# Below 767px viewports, the columns become fluid and stack vertically.
version :middle do
process :resize_to_fill => [742, 500]
def store_dir
ENV['STORAGE_PATH'] + "/thumbs/#{model.album.path}/#{model.id}"
end
end
version :large do
process :resize_to_fill => [940, 600]
def store_dir
ENV['STORAGE_PATH'] + "/thumbs/#{model.album.path}/#{model.id}"
end
end
version :largest do
process :resize_to_fill => [1170, 600]
def store_dir
ENV['STORAGE_PATH'] + "/thumbs/#{model.album.path}/#{model.id}"
end
end
######################################################################################################################
# Add a white list of extensions which are allowed to be uploaded,
# for images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png bmp tiff)
end
end

View File

@ -1,28 +0,0 @@
class UserpicUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
def store_dir
"#{ENV['STORAGE_PATH']}/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}/original"
end
def filename
"#{::SecureRandom.hex(8)}#{File.extname(original_filename).downcase}" if original_filename
end
version :mini do
process :resize_to_fit => [50, 50]
def store_dir
"#{ENV['STORAGE_PATH']}/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}/mini"
end
end
version :small do
process :resize_to_fit => [100, 100]
def store_dir
"#{ENV['STORAGE_PATH']}/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}/small"
end
end
end

View File

@ -1 +0,0 @@
<p><%= render :partial => "photos/thumb", :locals => { :photo => album.photos.find(:first), :photosize => 'collection' } unless album.photos.empty? %></p>

View File

@ -1,63 +0,0 @@
<%= content_for :javascript do %>
<%= javascript_include_tag "http://maps.google.com/maps/api/js?sensor=true" -%>
<%= javascript_include_tag "tag/tag" -%>
<% end %>
<div id="map_canvas"></div>
<fieldset>
<%= hidden_field_tag :all_tags, "'#{Tag.all.map { |tag| tag.title }.join('\',\'')}'" %>
<%= hidden_field_tag :collection_id, params[:collection_id] %>
<%= form.hidden_field :id %>
<%= form.hidden_field :latitude %>
<%= form.hidden_field :longitude %>
<div class="control-group">
<%= form.label :title, t('activerecord.models.album.attributes.title'), {:class => 'control-label'} %>
<div class="controls">
<%= form.text_field :title, {:class => 'input-xlarge'} %>
</div>
</div>
<div class="control-group">
<%= form.label :description, t('activerecord.models.album.attributes.description'), {:class => 'control-label'} %>
<div class="controls">
<%= form.text_area :description, {:class => 'input-xlarge', :rows => 5} %>
</div>
</div>
<div class="control-group">
<%= form.label :public, t('activerecord.models.album.attributes.visible'), {:class => 'control-label'} %>
<div class="controls">
<label class="checkbox">
<%= check_box 'collection', :public %> <%= t(:make_visible_for_all) %>
</label>
</div>
</div>
<div class="control-group">
<%= form.label :address, t('activerecord.models.album.attributes.address'), {:class => 'control-label'} %>
<div class="controls">
<%= form.text_area :address, {:class => 'input-xlarge', :rows => 5} %>
</div>
</div>
<div class="control-group">
<%= form.label :note, t('activerecord.models.album.attributes.note'), {:class => 'control-label'} %>
<div class="controls">
<%= form.text_area :note, {:class => 'input-xlarge', :rows => 5} %>
</div>
</div>
<div class="control-group">
<%= form.label :tags, t('activerecord.models.album.attributes.tags'), {:class => 'control-label'} %>
<div class="controls">
<%= form.text_field :tags, {:class => 'input-xlarge', :autocomplete => "off", :class => 'tag_list', :value => (@album.tags.map{|tag|tag.title}.join(" ") unless @album.tags.nil?) } %>
</div>
</div>
<br />
Contains: <%= @album.photos.count %> photos<br/>
</fieldset>

View File

@ -1,28 +0,0 @@
<div class="row">
<div class="span12">
<% @albums.in_groups_of(4).each do |group| %>
<% unless group.empty? %>
<ul class="thumbnails">
<% group.compact.each_with_index do |album, index| %>
<li class="span3">
<div class="thumbnail">
<%= image_tag album.photos.first.attachment.thumb.url %>
<div class="caption">
<h5 class="title"><%= album.title %></h5>
<em class="descr"><%= album.description %></em>
<div class="controls">
<p class="view-btn"><%= link_to 'View', (album_path(album) unless album.photos.empty?), {:class => 'btn btn-primary'} %></p>
<div class="tooltips">
<span rel="popover" class="icon-th icon-popover" data-content="<%= t(:photos_counter, :count => album.photos.count) %>"></span>
</div>
<%= ratings_for album %>
</div>
</div>
</div>
</li>
<% end %>
</ul>
<% end %>
<% end %>
</div>
</div>

View File

@ -1,17 +0,0 @@
<h1>Edit Album</h1>
<%= form_for @album do |f| %>
<%= f.error_messages %>
<%= render :partial => "form", :object => f %>
<%= f.submit "Update" %>
<% end %>
<%= content_for :action_links do %>
<% if has_role?("admin") %>
<%= link_to("Delete album", { :action => "destroy", :id => @album, :collection_id => params[:collection_id] },
:confirm => "Are you sure you want to delete this album?",
:method => :delete) %>
<% end %>
<% end %>

View File

@ -1,11 +0,0 @@
<%= paginate @albums %>
<%= render 'row_collections' %>
<%= paginate @albums %>
<%= content_for :action_links do %>
<%= link_to "Show just the photos tagged with #{params[:q]}", photos_path(:q => params[:q]) if params[:q] %>
<% if current_user and current_user.has_role?("admin") %>
<%= " |&nbsp;" if params[:q] %>
<%= link_to "New album", new_album_path() %>
<% end %>
<% end %>

View File

@ -1,9 +0,0 @@
<%= form_for @album, :html => {:class => 'form-horizontal'} do |f| %>
<legend><%= t('activerecord.actions.new', :model => I18n.t('activerecord.models.album.one')) %></legend>
<%= f.error_messages %>
<%= render :partial => "form", :object => f %>
<div class="form-actions">
<%= f.button "Create", :class => 'btn btn-primary btn-large' %>
</div>
<% end %>

View File

@ -1,47 +0,0 @@
<h2><%= @album.title %></h2>
<%= render :partial => 'photos/row_collections' %>
<p><%= @album.description %></p>
<% unless @album.photo_tags.empty? %>
<p>Tagged with:
<% for tag in @album.photo_tags.map { |tag| tag.title }.sort %>
<%= link_to tag, album_tag_photos_path(@album, tag) %>
<% end %>
</p>
<% end %>
<% unless @album.collections.empty? %>
<p>Part of:
<% for collection in @album.collections.order('title') %>
<%= link_to collection.title, collection_path(collection) %>
<% end %>
</p>
<% end %>
<% if current_user and current_user.has_role?("admin") %>
<p><%= @album.address %></p>
<p><%= @album.note %></p>
<% end %>
<%= content_for :action_links do %>
<% if current_user and current_user.has_role?("admin") %>
<% if params[:collection_id] %>
<li><%= link_to "PDF", collection_album_path(params[:collection_id], @album, :format => 'pdf') %></li>
<li><%= link_to "Edit album", edit_collection_album_path(params[:collection_id], @album) %></li>
<li><%= link_to "Edit all photos", edit_multiple_collection_album_photos_path(params[:collection_id], @album) %></li>
<li><%= link_to "Edit untouched photos", untouched_collection_album_photos_path(params[:collection_id], @album) %></li>
<li><%= link_to "Add photos", upload_collection_album_photos_path(params[:collection_id], @album) %></li>
<% else %>
<li><%= link_to "PDF", album_path(@album, :format => 'pdf') %></li>
<li><%= link_to "Edit album", edit_album_path(@album) %></li>
<li><%= link_to "Edit all photos", edit_multiple_album_photos_path(@album) %></li>
<li><%= link_to "Edit untouched photos", untouched_album_photos_path(@album) %></li>
<li><%= link_to "Add photos", upload_album_photos_path(@album) %></li>
<% end %>
<% end %>
<% end %>

View File

@ -1,3 +0,0 @@
<h1><%= @album.title %></h1>
<%= render :partial => @album.photos %>

View File

@ -1,11 +0,0 @@
<% for album in @albums %>
<div class="row">
<div class="title">
<%= render :partial => "photos/thumb", :locals => {:photo => album.photos.first } unless album.photos.empty? %>
<p><%= link_to album.title, album %></p>
</div>
<div class="image">
<%= render :partial => "photos/thumb", :collection => album.photos.find(:all, :limit => 5, :offset => 1), :as => :photo %>
</div>
</div>
<% end %>

View File

@ -1,49 +0,0 @@
<fieldset>
<div class="control-group">
<%= form.label :title, t('activerecord.models.collection.attributes.title'), {:class => 'control-label'} %>
<div class="controls">
<%= form.text_field :title, {:class => 'input-xlarge'} %>
</div>
</div>
<div class="control-group">
<%= form.label :description, t('activerecord.models.collection.attributes.description'), {:class => 'control-label'} %>
<div class="controls">
<%= form.text_area :description, {:class => 'input-xlarge', :rows => 5} %>
</div>
</div>
<div class="control-group">
<%= form.label :public, t('activerecord.models.collection.attributes.visible'), {:class => 'control-label'} %>
<div class="controls">
<label class="checkbox">
<%= check_box 'collection', :public %> <%= t(:make_visible_for_all) %>
</label>
</div>
</div>
<% unless @collection.albums.empty? %>
<%= form.label :albums %>
<% @collection.albums.each do |album| %>
<%= form.fields_for :album_list do |album_fields| %>
<%= image_tag "delete-24x24.png", :class => "delete", :alt => "Delete" -%>
<% if album.photos.empty? %>
<%= album.title %>
<% else %>
<%= image_tag album.photos.first.attachment.thumb.url, :alt => album.title %>
<% end %>
<%= album_fields.hidden_field album.id %>
<% end %>
<% end %>
<%
grouped_options = [
['Available albums', [['Choose album to add', '']]],
['Not used', Album.unused.map { |album| [album.title, album.id] }],
['In use', Album.used.map { |album| [album.title, album.id] }]
]
grouped_options_for_select(grouped_options)
%>
<%= select_tag 'available_albums', grouped_options_for_select(grouped_options) %>
<% end %>
</fieldset>

View File

@ -1,29 +0,0 @@
<div class="row">
<div class="span12">
<% @collections.in_groups_of(4).each do |group| %>
<% unless group.empty? %>
<ul class="thumbnails">
<% group.compact.each_with_index do |collection, index| %>
<li class="span3">
<div class="thumbnail">
<%= image_tag collection.albums.first.photos.first.attachment.thumb.url %>
<div class="caption">
<h5 class="title"><%= collection.title %></h5>
<em class="descr"><%= collection.description %></em>
<div class="controls">
<p class="view-btn"><%= link_to 'View', (collection_path(collection) unless collection.albums.empty? || collection.albums.first.photos.empty?), {:class => 'btn btn-primary'} %></p>
<div class="tooltips">
<span rel="popover" class="icon-th-large icon-popover" data-content="<%= t(:albums_counter, :count => collection.albums.size) %>"></span>
<span rel="popover" class="icon-th icon-popover" data-content="<%= t(:photos_counter, :count => collection.photos_count) %>"></span>
</div>
<%= ratings_for collection %>
</div>
</div>
</div>
</li>
<% end %>
</ul>
<% end %>
<% end %>
</div>
</div>

View File

@ -1,13 +0,0 @@
<h1>Edit collection</h1>
<%= form_for @collection do |f| %>
<%= f.error_messages %>
<%= render :partial => "form", :object => f %>
<%= f.submit "Update" %>
<% end %>
<%= content_for :action_links do %>
<%= link_to("Delete this collection", { :action => "destroy", :id => @collection },
:confirm => "Are you sure you want to delete this collection?",
:method => :delete) %>
<% end %>

View File

@ -1,6 +0,0 @@
<h1><%= t('activerecord.models.collection.pluralize') %></h1>
<%= paginate @collections %>
<%= render 'row_collections' %>
<%= paginate @collections %>

View File

@ -1,8 +0,0 @@
<%= form_for @collection, :html => {:class => 'form-horizontal'} do |f| %>
<legend><%= t('activerecord.actions.new', :model => I18n.t('activerecord.models.collection.one')) %></legend>
<%= f.error_messages %>
<%= render :partial => "form", :object => f %>
<div class="form-actions">
<%= f.button "Create", :class => 'btn btn-primary btn-large' %>
</div>
<% end %>

View File

@ -1,12 +0,0 @@
<h2><%= @collection.title %></h2>
<p><%= @collection.description %></p>
<%= render :partial => 'albums/row_collections' %>
<%= content_for :action_links do %>
<% if current_user and current_user.has_role?("admin") %>
<li><%= link_to "PDF", collection_path(@collection, :format => 'pdf') %></li>
<li><%= link_to "Edit collection", edit_collection_path(@collection) %></li>
<li><%= link_to "New album", new_collection_album_path(@collection) %></li>
<% end %>
<% end %>

View File

@ -1,8 +0,0 @@
<h2><%= h @collection.title %></h2>
<p><%= h @collection.description %></p>
<% for album in @collection.albums %>
<h3><%= album.title %></h3>
<p><%= render :partial => album.photos %></p>
<% end %>

View File

@ -1,24 +0,0 @@
<%- if controller_name != 'sessions' %>
<%= link_to t('devise.sign_in'), login_path %><br />
<% end -%>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to t('devise.sign_up'), signup_path %><br />
<% end -%>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
<%= link_to t('devise.forgot_your_password'), new_password_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
<%= link_to t('devise.send_confirmation_instructions'), new_confirmation_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
<%= link_to t('devise.send_unlock_instructions'), new_unlock_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to t('devise.sign_in_with', :provider => provider.to_s.titleize), omniauth_authorize_path(resource_name, provider) %><br />
<% end -%>
<% end -%>

View File

@ -1,12 +0,0 @@
<h2>Resend confirmation instructions</h2>
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.submit "Resend confirmation instructions" %></div>
<% end %>
<%= render "links" %>

View File

@ -1,5 +0,0 @@
<p>Welcome <%= @resource.email %>!</p>
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>

View File

@ -1,8 +0,0 @@
<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>

View File

@ -1,7 +0,0 @@
<p>Hello <%= @resource.email %>!</p>
<p>Your account has been locked due to an excessive amount of unsuccessful sign in attempts.</p>
<p>Click the link below to unlock your account:</p>
<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %></p>

View File

@ -1,16 +0,0 @@
<h2>Change your password</h2>
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<%= f.hidden_field :reset_password_token %>
<div><%= f.label :password, "New password" %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation, "Confirm new password" %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Change my password" %></div>
<% end %>
<%= render "links" %>

View File

@ -1,12 +0,0 @@
<h2>Forgot your password?</h2>
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.submit "Send me reset password instructions" %></div>
<% end %>
<%= render "links" %>

View File

@ -1,25 +0,0 @@
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, :autocomplete => "off" %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %></div>
<div><%= f.submit "Update" %></div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.</p>
<%= link_to "Back", :back %>

View File

@ -1,18 +0,0 @@
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "links" %>

View File

@ -1,17 +0,0 @@
<h2><%= t("devise.sign_in") %></h2>
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<div><%= f.submit "Sign in" %></div>
<% end %>
<%= render "links" %>

View File

@ -1,12 +0,0 @@
<h2>Resend unlock instructions</h2>
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.submit "Resend unlock instructions" %></div>
<% end %>
<%= render "links" %>

View File

@ -1,5 +0,0 @@
<div class="row">
<%= render 'shared/home_slider' %>
</div>
<h2><%= t('activerecord.models.collection.popular') %></h2>
<%= render :partial => 'collections/row_collections' %>

View File

@ -1,13 +0,0 @@
<%# Link to the "First" page
- available local variables
url: url to the first page
current_page: a page object for the currently displayed page
num_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<% unless current_page.first? %>
<li class="first">
<%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote %>
</li>
<% end %>

View File

@ -1,8 +0,0 @@
<%# Non-link tag that stands for skipped pages...
- available local variables
current_page: a page object for the currently displayed page
num_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<li class="page gap disabled"><a href="#" onclick="return false;"><%= raw(t 'views.pagination.truncate') %></a></li>

View File

@ -1,13 +0,0 @@
<%# Link to the "Last" page
- available local variables
url: url to the last page
current_page: a page object for the currently displayed page
num_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<% unless current_page.last? %>
<li class="last next"><%# "next" class present for border styling in twitter bootstrap %>
<%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} %>
</li>
<% end %>

View File

@ -1,13 +0,0 @@
<%# Link to the "Next" page
- available local variables
url: url to the next page
current_page: a page object for the currently displayed page
num_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<% unless current_page.last? %>
<li class="next_page">
<%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote %>
</li>
<% end %>

View File

@ -1,12 +0,0 @@
<%# Link showing page number
- available local variables
page: a page object for "this" page
url: url to this page
current_page: a page object for the currently displayed page
num_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<li class="page<%= ' active' if page.current? %>">
<%= link_to page, url, opts = {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
</li>

View File

@ -1,25 +0,0 @@
<%# The container tag
- available local variables
current_page: a page object for the currently displayed page
num_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
paginator: the paginator that renders the pagination tags inside
-%>
<%= paginator.render do -%>
<div class="pagination">
<ul>
<%= first_page_tag unless current_page.first? %>
<%= prev_page_tag unless current_page.first? %>
<% each_page do |page| -%>
<% if page.left_outer? || page.right_outer? || page.inside_window? -%>
<%= page_tag page %>
<% elsif !page.was_truncated? -%>
<%= gap_tag %>
<% end -%>
<% end -%>
<%= next_page_tag unless current_page.last? %>
<%= last_page_tag unless current_page.last? %>
</ul>
</div>
<% end -%>

View File

@ -1,13 +0,0 @@
<%# Link to the "Previous" page
- available local variables
url: url to the previous page
current_page: a page object for the currently displayed page
num_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<% unless current_page.first? %>
<li class="prev">
<%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
</li>
<% end %>

View File

@ -1,42 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<%= render :partial => 'shared/head' %>
</head>
<body>
<div id="container">
<div id="header">
<div id="action_links">
<%= yield :action_links %>
<% if current_user %>
Logged in as <%= current_user.name %>
<%= link_to 'Logout', logout_path %>
<% end %>
</div>
<h1>
<%= link_to(if ENV['LOGO'] then image_tag(ENV['LOGO']) else (ENV['TITLE'] || "Photos") end, root_path) %>
</h1>
<%= form_tag albums_path, { :id => :search } do -%>
<input type="text" name="q" class="textfield"/>
<input type="submit" value="Search" class="button" />
<% end -%>
<hr class="seperator" />
<%= breadcrumbs %>
</div>
<div id="content">
<p id="notice"><%= flash[:notice] %></p>
<%= yield %>
</div>
<div id="footer">
<hr class="seperator" />
&copy; <a href="http://balderapp.com">Balder - open source photo gallery</a>.
</div>
</div>
</body>
</html>

View File

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<%= render :partial => 'shared/head' %>
</head>
<body>
<%= render :partial => 'shared/nav_bar' %>
<div class="container">
<div class="row">
<div class="span12">
<%= render :partial => 'shared/notifications' %>
<%= render_breadcrumbs %>
<%= yield %>
</div>
</div>
<hr>
<footer>
<p>&copy; Photomix 2012</p>
</footer>
</div>
</body>
</html>

View File

@ -1,14 +0,0 @@
<%= content_for :javascript do %>
<%= javascript_include_tag "tag/tag" -%>
<% end %>
<%= hidden_field_tag :all_tags, @tags %>
<%= form.label :title %><br />
<%= form.text_field :title %><br />
<br/>
<%= form.label :tag_list %><br />
<%= form.text_field :tag_list, {:autocomplete => "off", :class => 'tag_list'} %><br />
<br/>
<%= form.label :description %><br />
<%= form.text_area :description %><br />
<br/>
<p>On disk: ~/<%= @photo.attachment.path %></p>

View File

@ -1 +0,0 @@
<%= image_tag photo.attachment.single.url %><br/>

View File

@ -1,22 +0,0 @@
<div class="row">
<div class="span12">
<% @photos.in_groups_of(4).each do |group| %>
<% unless group.empty? %>
<ul class="thumbnails">
<% group.compact.each_with_index do |photo, index| %>
<li class="span3">
<div class="thumbnail">
<%= link_to image_tag(photo.attachment.thumb.url), photo.attachment.largest.url, :class => 'fancybox-thumb', :rel => "fancybox-thumb" %>
<div class="caption">
<h5 class="title"><%= photo.title %></h5>
<em class="descr"><%= photo.description %></em>
<%= ratings_for photo %>
</div>
</div>
</li>
<% end %>
</ul>
<% end %>
<% end %>
</div>
</div>

View File

@ -1 +0,0 @@
<%= link_to image_tag(eval('photo.attachment.' + (defined?(photosize) ? photosize : "thumb") + '.url')), [photo.album.collections.first, photo.album, photo] %>

View File

@ -1,17 +0,0 @@
<h1>Edit Photo</h1>
<%= image_tag @photo.attachment.preview.url %>
<%= form_for @photo do |f| %>
<%= hidden_field_tag :collection_id, params[:collection_id] %>
<%= hidden_field_tag :album_id, params[:album_id] %>
<%= f.error_messages %>
<%= render :partial => "form", :object => f %>
<%= f.submit "Update" %>
<% end %>
<%= content_for :action_links do %>
<%= link_to("Delete photo", {:action => "destroy", :id => @photo, :collection_id => params[:collection_id]},
:confirm => "Are you sure you want to delete this photo?",
:method => :delete) %>
<% end %>

View File

@ -1,15 +0,0 @@
<%= form_for :photos, :url => update_multiple_photos_path, :html => {:method => :put} do |f| %>
<% for photo in @photos %>
<p>
<%= f.fields_for photo, :index => photo.id do |p| %>
<%= p.check_box :_delete %>
<%= render :partial => "photos/thumb", :locals => {:photo => photo} %>
<%= p.text_field :title %>
<%= p.text_field :tags, :value => photo.tag_list %>
<% end %>
</p>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
<br/><%= link_to "Back to #{@album.title}", @album %>

View File

@ -1,9 +0,0 @@
<%#= render :partial => 'photos/thumb', :collection => @photos, :as => :photo %>
<%= paginate @photos %>
<%= render :partial => 'photos/row_collections' %>
<%= paginate @photos %>
<%= content_for :action_links do %>
<%= link_to "Show albums containing photos tagged with #{params[:q]}", albums_path(:q => params[:q]) if params[:q] %>
<%= link_to "Show all photos tagged with #{params[:tag_id]}", tag_photos_path(params[:tag_id]) if params[:tag_id] && params[:album_id] %>
<% end %>

View File

@ -1,34 +0,0 @@
<h2><%= @photo.title %></h2>
<div id="fullimage">
<div id="navigation">
<p class="links">
<% unless @previous.nil? %>
<%= link_to "Previous", [@photo.album.collections.first, @photo.album, @previous] %>
<% unless @next.nil? %>
|
<% end %>
<% end %>
<% unless @next.nil? %>
<%= link_to "Next", [@photo.album.collections.first, @photo.album, @next] %>
<% end %>
</p>
</div>
<p><%= link_to_if @next, image_tag(@photo.attachment.single.url), [@photo.album.collections.first, @photo.album, @next] %></p>
</div>
<p><%= @photo.description %></p>
<p>Tagged with:
<% for tag in @photo.tags.map { |tag| tag.title }.sort %>
<%= link_to tag, tag_photos_path(tag) %>
<% end %>
<%= content_for :action_links do %>
<% if current_user and current_user.has_role?("admin") %>
<% if params[:collection_id] %>
<%= link_to "Edit photo", edit_collection_album_photo_path(params[:collection_id], params[:album_id], @photo) %>
<% else %>
<%= link_to "Edit photo", edit_photo_path(@photo) %>
<% end %>
<% end %>
<% end %>

View File

@ -1,12 +0,0 @@
<%= form_for :photos, :url => update_multiple_photos_path, :html => {:method => :put} do |f| %>
<% for photo in @photos %>
<p>
<%= f.fields_for photo do |p| %>
<%= render :partial => "photos/thumb", :locals => {:photo => photo} %>
<%= p.text_field :title, :index => photo.id %>
<%= p.text_field :tags, :index => photo.id, :value => photo.tag_list %>
<% end %>
</p>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>

View File

@ -1,78 +0,0 @@
<%= content_for :javascript do %>
<script type="text/javascript">
$(document).ready(function () {
$("#uploader").pluploadQueue({
runtimes:'flash,html5,browserplus,silverlight,gears',
url:'<%= photos_path %>',
max_file_size:'10mb',
multipart:true,
multipart_params:{
'<%= get_session_key %>':encodeURIComponent('<%= cookies[get_session_key] %>'),
'authenticity_token':'<%= form_authenticity_token %>',
'photo[album_id]':"<%= @album.id %>"
},
// Resize images on clientside if we can
//resize : {width : 320, height : 240, quality : 90},
// Specify what files to browse for
filters:[
{title:"Image files", extensions:"jpg,gif,png,bmp,jpeg,tif,tiff,JPG,GIF,PNG,BMP,JPEG,TIF,TIFF"}
],
// Flash settings
flash_swf_url:'/assets/plupload.flash.swf',
// Silverlight settings
silverlight_xap_url:'/assets/plupload.silverlight.xap',
// Post init events, bound after the internal events
init:{
FileUploaded:function (up, file, info) {
// Called when a file has finished uploading
res = info.response;
if (res.substring(0, 7) === "FILEID:") {
var image = $('<img>').appendTo('#thumbs')
image.css('display', 'none')
image.attr('src', res.substring(7))
image.fadeIn('slow')
}
}
}
});
// Client side form validation
$('form').submit(function (e) {
var uploader = $('#uploader').pluploadQueue();
// Validate number of uploaded files
if (uploader.total.uploaded == 0) {
// Files in queue upload them first
if (uploader.files.length > 0) {
// When all files are uploaded submit form
uploader.bind('UploadProgress', function () {
if (uploader.total.uploaded == uploader.files.length)
$('form').submit();
});
uploader.start();
} else
alert('You must at least upload one file.');
e.preventDefault();
}
});
})
</script>
<% end %>
<form>
<div id="uploader">
<p>You browser doesn't have Flash, Silverlight, Gears, BrowserPlus or HTML5 support.</p>
</div>
<br>
<div id="thumbs"></div>
</form>
<br><%= link_to "Edit uploaded photos", untouched_album_photos_path(@album) %>
<br><%= link_to "Back to #{@album.title}", @album %>

View File

@ -1,40 +0,0 @@
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= ENV['TITLE'] || "Photos" %></title>
<%= csrf_meta_tags %>
<!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
<![endif]-->
<%= yield :styles %>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= yield :head %>
<!-- For third-generation iPad with high-resolution Retina display: -->
<!-- Size should be 144 x 144 pixels -->
<%#= favicon_link_tag 'images/apple-touch-icon-144x144-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '144x144' %>
<!-- For iPhone with high-resolution Retina display: -->
<!-- Size should be 114 x 114 pixels -->
<%#= favicon_link_tag 'images/apple-touch-icon-114x114-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '114x114' %>
<!-- For first- and second-generation iPad: -->
<!-- Size should be 72 x 72 pixels -->
<%#= favicon_link_tag 'images/apple-touch-icon-72x72-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '72x72' %>
<!-- For non-Retina iPhone, iPod Touch, and Android 2.1+ devices: -->
<!-- Size should be 57 x 57 pixels -->
<%#= favicon_link_tag 'images/apple-touch-icon-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png' %>
<!-- For all other devices -->
<!-- Size should be 32 x 32 pixels -->
<%#= favicon_link_tag 'images/favicon.ico', :rel => 'shortcut icon' %>
<%= yield :javascript %>
<%= raw ajaxful_rating_style %>
<%= raw ajaxful_rating_script %>

Some files were not shown because too many files have changed in this diff Show More