better way of handling albums in collection
This commit is contained in:
parent
d9607ea0c8
commit
2b9f8b41a8
10 changed files with 341 additions and 18 deletions
|
@ -13,7 +13,9 @@ class Album < ActiveRecord::Base
|
|||
attr_accessor :tags
|
||||
attr_protected :path
|
||||
|
||||
named_scope :untouched, :conditions => "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'
|
||||
named_scope :untouched, :conditions => "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'
|
||||
named_scope :unused, :conditions => "albums.id NOT IN (SELECT album_id FROM collection_albums)"
|
||||
named_scope :used, :conditions => "albums.id IN (SELECT album_id FROM collection_albums)"
|
||||
|
||||
def to_param
|
||||
"#{id}-#{title.parameterize}"
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
class Collection < ActiveRecord::Base
|
||||
has_many :collection_albums
|
||||
has_many :albums, :through => :collection_albums
|
||||
#accepts_nested_attributes_for :albums, :allow_destroy => true
|
||||
attr_accessor :album_list
|
||||
|
||||
def to_param
|
||||
#title.gsub(/[^a-z0-9]+/i, '-')
|
||||
"#{id}-#{title.parameterize}"
|
||||
end
|
||||
|
||||
|
||||
def album_list=(albums)
|
||||
self.albums = Album.find(albums)
|
||||
self.albums = Album.find(albums.map{|album|album[0]})
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
|
@ -4,5 +4,28 @@
|
|||
<%= form.label :description %><br />
|
||||
<%= form.text_area :description %><br />
|
||||
|
||||
<%= form.label :album %><br />
|
||||
<%= collection_select :collection, :album_list, Album.find(:all, :order => :title), :id, :title, {:selected => @collection.albums.map{|album|album.id} }, {:multiple => true, :rows => 10} %><br />
|
||||
<%= form.label :albums %><br />
|
||||
|
||||
<div id="collection_albums">
|
||||
<% for album in @collection.albums %>
|
||||
<% form.fields_for :album_list do |album_fields| %>
|
||||
<span>
|
||||
<img src="/images/delete-24x24.png" border="" class="delete" />
|
||||
<%= image_tag album.photos.first.path_modified_public('album'), :alt => album.title %>
|
||||
<%= album_fields.hidden_field album.id %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<p class="clear">
|
||||
<%
|
||||
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) %>
|
||||
</p>
|
|
@ -41,7 +41,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<%= javascript_include_tag 'jquery-1.3.2.js', 'application' %>
|
||||
<%= javascript_include_tag 'jquery-1.3.2.js', 'jquery.livequery.js', 'balder' %>
|
||||
<%= yield :javascript %>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -14,4 +14,6 @@ config.action_view.debug_rjs = true
|
|||
config.action_controller.perform_caching = false
|
||||
|
||||
# Don't care if the mailer can't send
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
ENV["RAILS_ASSET_ID"] = ""
|
|
@ -1,18 +1,18 @@
|
|||
development:
|
||||
site_name: Photos
|
||||
photos_path: 'photos'
|
||||
thumbs_path: 'public/thumbs/'
|
||||
photos_path: <%= RAILS_ROOT + '/photos/' %>
|
||||
thumbs_path: <%= RAILS_ROOT + '/public/thumbs/' %>
|
||||
photos_path_public: '/files/'
|
||||
thumbs_path_public: '/thumbs/'
|
||||
production:
|
||||
site_name: Photos
|
||||
photos_path: 'photos'
|
||||
thumbs_path: 'public/thumbs/'
|
||||
photos_path: <%= RAILS_ROOT + '/photos/' %>
|
||||
thumbs_path: <%= RAILS_ROOT + '/public/thumbs/' %>
|
||||
photos_path_public: '/files/'
|
||||
thumbs_path_public: '/thumbs/'
|
||||
test:
|
||||
site_name: Photos
|
||||
photos_path: 'photos'
|
||||
thumbs_path: 'public/thumbs/'
|
||||
photos_path: <%= RAILS_ROOT + '/photos/' %>
|
||||
thumbs_path: <%= RAILS_ROOT + '/public/thumbs/' %>
|
||||
photos_path_public: '/files/'
|
||||
thumbs_path_public: '/thumbs/'
|
BIN
public/images/delete-24x24.png
Normal file
BIN
public/images/delete-24x24.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -17,6 +17,32 @@ jQuery(function($) {
|
|||
mapInitialize()
|
||||
$('#map_canvas').show()
|
||||
}
|
||||
|
||||
$('#collection_albums .delete').livequery('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){
|
||||
html = '<span style="display:none;"><img src="/images/delete-24x24.png" border="" class="delete" />'
|
||||
html += '<img alt="' + $("#available_albums :selected").val() + '_collection" src="/thumbs/' + $("#available_albums :selected").text() + '/' + data[0].photo.id + '_album.jpg" />'
|
||||
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 ) {
|
250
public/javascripts/jquery.livequery.js
Normal file
250
public/javascripts/jquery.livequery.js
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*! Copyright (c) 2008 Brandon Aaron (http://brandonaaron.net)
|
||||
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
||||
*
|
||||
* Version: 1.0.3
|
||||
* Requires jQuery 1.1.3+
|
||||
* Docs: http://docs.jquery.com/Plugins/livequery
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.extend($.fn, {
|
||||
livequery: function(type, fn, fn2) {
|
||||
var self = this, q;
|
||||
|
||||
// Handle different call patterns
|
||||
if ($.isFunction(type))
|
||||
fn2 = fn, fn = type, type = undefined;
|
||||
|
||||
// See if Live Query already exists
|
||||
$.each( $.livequery.queries, function(i, query) {
|
||||
if ( self.selector == query.selector && self.context == query.context &&
|
||||
type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) )
|
||||
// Found the query, exit the each loop
|
||||
return (q = query) && false;
|
||||
});
|
||||
|
||||
// Create new Live Query if it wasn't found
|
||||
q = q || new $.livequery(this.selector, this.context, type, fn, fn2);
|
||||
|
||||
// Make sure it is running
|
||||
q.stopped = false;
|
||||
|
||||
// Run it immediately for the first time
|
||||
q.run();
|
||||
|
||||
// Contnue the chain
|
||||
return this;
|
||||
},
|
||||
|
||||
expire: function(type, fn, fn2) {
|
||||
var self = this;
|
||||
|
||||
// Handle different call patterns
|
||||
if ($.isFunction(type))
|
||||
fn2 = fn, fn = type, type = undefined;
|
||||
|
||||
// Find the Live Query based on arguments and stop it
|
||||
$.each( $.livequery.queries, function(i, query) {
|
||||
if ( self.selector == query.selector && self.context == query.context &&
|
||||
(!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped )
|
||||
$.livequery.stop(query.id);
|
||||
});
|
||||
|
||||
// Continue the chain
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
$.livequery = function(selector, context, type, fn, fn2) {
|
||||
this.selector = selector;
|
||||
this.context = context || document;
|
||||
this.type = type;
|
||||
this.fn = fn;
|
||||
this.fn2 = fn2;
|
||||
this.elements = [];
|
||||
this.stopped = false;
|
||||
|
||||
// The id is the index of the Live Query in $.livequery.queries
|
||||
this.id = $.livequery.queries.push(this)-1;
|
||||
|
||||
// Mark the functions for matching later on
|
||||
fn.$lqguid = fn.$lqguid || $.livequery.guid++;
|
||||
if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;
|
||||
|
||||
// Return the Live Query
|
||||
return this;
|
||||
};
|
||||
|
||||
$.livequery.prototype = {
|
||||
stop: function() {
|
||||
var query = this;
|
||||
|
||||
if ( this.type )
|
||||
// Unbind all bound events
|
||||
this.elements.unbind(this.type, this.fn);
|
||||
else if (this.fn2)
|
||||
// Call the second function for all matched elements
|
||||
this.elements.each(function(i, el) {
|
||||
query.fn2.apply(el);
|
||||
});
|
||||
|
||||
// Clear out matched elements
|
||||
this.elements = [];
|
||||
|
||||
// Stop the Live Query from running until restarted
|
||||
this.stopped = true;
|
||||
},
|
||||
|
||||
run: function() {
|
||||
// Short-circuit if stopped
|
||||
if ( this.stopped ) return;
|
||||
var query = this;
|
||||
|
||||
var oEls = this.elements,
|
||||
els = $(this.selector, this.context),
|
||||
nEls = els.not(oEls);
|
||||
|
||||
// Set elements to the latest set of matched elements
|
||||
this.elements = els;
|
||||
|
||||
if (this.type) {
|
||||
// Bind events to newly matched elements
|
||||
nEls.bind(this.type, this.fn);
|
||||
|
||||
// Unbind events to elements no longer matched
|
||||
if (oEls.length > 0)
|
||||
$.each(oEls, function(i, el) {
|
||||
if ( $.inArray(el, els) < 0 )
|
||||
$.event.remove(el, query.type, query.fn);
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Call the first function for newly matched elements
|
||||
nEls.each(function() {
|
||||
query.fn.apply(this);
|
||||
});
|
||||
|
||||
// Call the second function for elements no longer matched
|
||||
if ( this.fn2 && oEls.length > 0 )
|
||||
$.each(oEls, function(i, el) {
|
||||
if ( $.inArray(el, els) < 0 )
|
||||
query.fn2.apply(el);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.extend($.livequery, {
|
||||
guid: 0,
|
||||
queries: [],
|
||||
queue: [],
|
||||
running: false,
|
||||
timeout: null,
|
||||
|
||||
checkQueue: function() {
|
||||
if ( $.livequery.running && $.livequery.queue.length ) {
|
||||
var length = $.livequery.queue.length;
|
||||
// Run each Live Query currently in the queue
|
||||
while ( length-- )
|
||||
$.livequery.queries[ $.livequery.queue.shift() ].run();
|
||||
}
|
||||
},
|
||||
|
||||
pause: function() {
|
||||
// Don't run anymore Live Queries until restarted
|
||||
$.livequery.running = false;
|
||||
},
|
||||
|
||||
play: function() {
|
||||
// Restart Live Queries
|
||||
$.livequery.running = true;
|
||||
// Request a run of the Live Queries
|
||||
$.livequery.run();
|
||||
},
|
||||
|
||||
registerPlugin: function() {
|
||||
$.each( arguments, function(i,n) {
|
||||
// Short-circuit if the method doesn't exist
|
||||
if (!$.fn[n]) return;
|
||||
|
||||
// Save a reference to the original method
|
||||
var old = $.fn[n];
|
||||
|
||||
// Create a new method
|
||||
$.fn[n] = function() {
|
||||
// Call the original method
|
||||
var r = old.apply(this, arguments);
|
||||
|
||||
// Request a run of the Live Queries
|
||||
$.livequery.run();
|
||||
|
||||
// Return the original methods result
|
||||
return r;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
run: function(id) {
|
||||
if (id != undefined) {
|
||||
// Put the particular Live Query in the queue if it doesn't already exist
|
||||
if ( $.inArray(id, $.livequery.queue) < 0 )
|
||||
$.livequery.queue.push( id );
|
||||
}
|
||||
else
|
||||
// Put each Live Query in the queue if it doesn't already exist
|
||||
$.each( $.livequery.queries, function(id) {
|
||||
if ( $.inArray(id, $.livequery.queue) < 0 )
|
||||
$.livequery.queue.push( id );
|
||||
});
|
||||
|
||||
// Clear timeout if it already exists
|
||||
if ($.livequery.timeout) clearTimeout($.livequery.timeout);
|
||||
// Create a timeout to check the queue and actually run the Live Queries
|
||||
$.livequery.timeout = setTimeout($.livequery.checkQueue, 20);
|
||||
},
|
||||
|
||||
stop: function(id) {
|
||||
if (id != undefined)
|
||||
// Stop are particular Live Query
|
||||
$.livequery.queries[ id ].stop();
|
||||
else
|
||||
// Stop all Live Queries
|
||||
$.each( $.livequery.queries, function(id) {
|
||||
$.livequery.queries[ id ].stop();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Register core DOM manipulation methods
|
||||
$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove');
|
||||
|
||||
// Run Live Queries when the Document is ready
|
||||
$(function() { $.livequery.play(); });
|
||||
|
||||
|
||||
// Save a reference to the original init method
|
||||
var init = $.prototype.init;
|
||||
|
||||
// Create a new init method that exposes two new properties: selector and context
|
||||
$.prototype.init = function(a,c) {
|
||||
// Call the original init and save the result
|
||||
var r = init.apply(this, arguments);
|
||||
|
||||
// Copy over properties if they exist already
|
||||
if (a && a.selector)
|
||||
r.context = a.context, r.selector = a.selector;
|
||||
|
||||
// Set properties
|
||||
if ( typeof a == 'string' )
|
||||
r.context = c || document, r.selector = a;
|
||||
|
||||
// Return the result
|
||||
return r;
|
||||
};
|
||||
|
||||
// Give the init function the jQuery prototype for later instantiation (needed after Rev 4091)
|
||||
$.prototype.init.prototype = $.prototype;
|
||||
|
||||
})(jQuery);
|
|
@ -1,3 +1,5 @@
|
|||
/* @override http://localhost:3000/stylesheets/application.css */
|
||||
|
||||
/* @group Reset */
|
||||
|
||||
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
|
||||
|
@ -65,6 +67,9 @@ caption {background:#eee;}
|
|||
.last {margin-right:0;padding-right:0;}
|
||||
.top {margin-top:0;padding-top:0;}
|
||||
.bottom {margin-bottom:0;padding-bottom:0;}
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -213,4 +218,23 @@ td {
|
|||
}
|
||||
p#notice {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
|
||||
DIV#collection_albums {
|
||||
width: 710px;
|
||||
clear: both;
|
||||
}
|
||||
DIV#collection_albums span {
|
||||
position: relative;
|
||||
display: block;
|
||||
float: left;
|
||||
padding: 5px;
|
||||
}
|
||||
DIV#collection_albums IMG.delete {
|
||||
display: block;
|
||||
vertical-align: top;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue