pelargir-image_picker 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +1 -0
- data/MIT-LICENSE +16 -0
- data/README +78 -0
- data/Rakefile +22 -0
- data/files/public/images/no_image.jpg +0 -0
- data/files/public/images/spinner.gif +0 -0
- data/files/public/javascripts/image_picker.js +21 -0
- data/files/public/javascripts/modalbox.js +573 -0
- data/files/public/stylesheets/modalbox.css +95 -0
- data/image_picker.gemspec +32 -0
- data/init.rb +3 -0
- data/install.rb +17 -0
- data/lib/image_picker.rb +11 -0
- data/lib/image_picker/controller.rb +28 -0
- data/lib/image_picker/link_renderer.rb +9 -0
- data/tasks/image_picker.rake +39 -0
- data/templates/open_picker.html.erb +38 -0
- metadata +70 -0
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
10/23/08 - Initial version [Matthew Bass]
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Copyright (c) 2007-2008 Matthew Bass (http://matthewbass.com)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
4
|
+
and associated documentation files (the "Software"), to deal in the Software without
|
5
|
+
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
6
|
+
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
7
|
+
Software is furnished to do so, subject to the following conditions:
|
8
|
+
|
9
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
10
|
+
substantial portions of the Software.
|
11
|
+
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
13
|
+
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
14
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
15
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
16
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
= image_picker
|
2
|
+
|
3
|
+
A simple, customizable image browser.
|
4
|
+
|
5
|
+
|
6
|
+
== Installation
|
7
|
+
|
8
|
+
Install the gem directly:
|
9
|
+
|
10
|
+
gem sources -a http://gems.github.com (you only have to do this once)
|
11
|
+
sudo gem install pelargir-image_picker
|
12
|
+
|
13
|
+
Or install the gem in your Rails project as a plugin:
|
14
|
+
|
15
|
+
script/plugin install git://github.com/pelargir/image_picker.git
|
16
|
+
|
17
|
+
Or clone the project:
|
18
|
+
|
19
|
+
git clone git://github.com/pelargir/image_picker.git
|
20
|
+
|
21
|
+
Then copy the required image, JS, and CSS files into your Rails project
|
22
|
+
|
23
|
+
rake image_picker:install_files
|
24
|
+
|
25
|
+
|
26
|
+
== Usage
|
27
|
+
|
28
|
+
First, add the picker to your view and pass it the name of the image
|
29
|
+
being picked. This name is used to create a hidden field that stores
|
30
|
+
the database ID of the image that gets picked:
|
31
|
+
|
32
|
+
<%= image_picker :avatar %>
|
33
|
+
|
34
|
+
Now tell your controller that you'll be picking images, and which
|
35
|
+
ActiveRecord model you'll be using:
|
36
|
+
|
37
|
+
class SomeController < ActionController::Base
|
38
|
+
image_picker :model => Image
|
39
|
+
end
|
40
|
+
|
41
|
+
The ActiveRecord class must respond to three method calls:
|
42
|
+
|
43
|
+
thumbnail: the path to the image's thumbnail (e.g. /images/foo_small.gif)
|
44
|
+
title: a friendly title for the image
|
45
|
+
description: a description of the image (optional)
|
46
|
+
|
47
|
+
That's it! The picker will show up in your view and, once you've
|
48
|
+
picked an image, its database ID will be set as the value of the
|
49
|
+
hidden field "<name>_id" where <name> is the name you passed
|
50
|
+
to the image_picker helper in your view. The hidden field can
|
51
|
+
then be submitted via a form or referenced in JavaScript.
|
52
|
+
|
53
|
+
|
54
|
+
== Other Options
|
55
|
+
|
56
|
+
The controller helper accepts any arguments you can pass to an
|
57
|
+
ActiveRecord finder. For example:
|
58
|
+
|
59
|
+
class SomeController < ActionController::Base
|
60
|
+
image_picker :model => Image, :order => "created_at DESC"
|
61
|
+
end
|
62
|
+
|
63
|
+
If the will_paginate plugin is installed, the image picker will
|
64
|
+
use it automatically. You can pass pagination options to the
|
65
|
+
controller helper as well. For example:
|
66
|
+
|
67
|
+
class SomeController < ActionController::Base
|
68
|
+
image_picker :model => Image, :per_page => 6
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
== Resources
|
73
|
+
|
74
|
+
Repository: http://github.com/pelargir/image_picker/
|
75
|
+
Blog: http://matthewbass.com
|
76
|
+
Author: Matthew Bass
|
77
|
+
|
78
|
+
Extraction work sponsored by Terralien
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the image_picker plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the image_picker plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'image_picker'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,21 @@
|
|
1
|
+
var ImagePicker = {
|
2
|
+
pick:function(field, image_id, image_title, image_url) {
|
3
|
+
$(field + '_id').value = image_id;
|
4
|
+
$(field).src = image_url;
|
5
|
+
$(field).alt = image_title;
|
6
|
+
Modalbox.hide();
|
7
|
+
},
|
8
|
+
|
9
|
+
clear:function(field, image_url) {
|
10
|
+
$(field + '_id').value = '';
|
11
|
+
$(field).src = image_url;
|
12
|
+
$(field).alt = 'No_image';
|
13
|
+
Modalbox.hide();
|
14
|
+
},
|
15
|
+
|
16
|
+
open_picker:function(params) {
|
17
|
+
url = $H(params).unset('url');
|
18
|
+
Modalbox.show(url + '?' + $H(params).toQueryString(),
|
19
|
+
{title: 'Select an image...', width: 520, afterLoad: ImagePicker.setup});
|
20
|
+
}
|
21
|
+
};
|
@@ -0,0 +1,573 @@
|
|
1
|
+
/*
|
2
|
+
ModalBox - The pop-up window thingie with AJAX, based on prototype and script.aculo.us.
|
3
|
+
|
4
|
+
Copyright Andrey Okonetchnikov (andrej.okonetschnikow@gmail.com), 2006-2007
|
5
|
+
All rights reserved.
|
6
|
+
|
7
|
+
VERSION 1.6.0
|
8
|
+
Last Modified: 12/13/2007
|
9
|
+
*/
|
10
|
+
|
11
|
+
if (!window.Modalbox)
|
12
|
+
var Modalbox = new Object();
|
13
|
+
|
14
|
+
Modalbox.Methods = {
|
15
|
+
overrideAlert: false, // Override standard browser alert message with ModalBox
|
16
|
+
focusableElements: new Array,
|
17
|
+
currFocused: 0,
|
18
|
+
initialized: false,
|
19
|
+
active: true,
|
20
|
+
options: {
|
21
|
+
title: "ModalBox Window", // Title of the ModalBox window
|
22
|
+
overlayClose: true, // Close modal box by clicking on overlay
|
23
|
+
width: 500, // Default width in px
|
24
|
+
height: 90, // Default height in px
|
25
|
+
overlayOpacity: .65, // Default overlay opacity
|
26
|
+
overlayDuration: .25, // Default overlay fade in/out duration in seconds
|
27
|
+
slideDownDuration: .5, // Default Modalbox appear slide down effect in seconds
|
28
|
+
slideUpDuration: .5, // Default Modalbox hiding slide up effect in seconds
|
29
|
+
resizeDuration: .25, // Default resize duration seconds
|
30
|
+
inactiveFade: true, // Fades MB window on inactive state
|
31
|
+
transitions: true, // Toggles transition effects. Transitions are enabled by default
|
32
|
+
loadingString: "Please wait. Loading...", // Default loading string message
|
33
|
+
closeString: "Close window", // Default title attribute for close window link
|
34
|
+
closeValue: "×", // Default string for close link in the header
|
35
|
+
params: {},
|
36
|
+
method: 'get', // Default Ajax request method
|
37
|
+
autoFocusing: true, // Toggles auto-focusing for form elements. Disable for long text pages.
|
38
|
+
aspnet: false // Should be use then using with ASP.NET costrols. Then true Modalbox window will be injected into the first form element.
|
39
|
+
},
|
40
|
+
_options: new Object,
|
41
|
+
|
42
|
+
setOptions: function(options) {
|
43
|
+
Object.extend(this.options, options || {});
|
44
|
+
},
|
45
|
+
|
46
|
+
_init: function(options) {
|
47
|
+
// Setting up original options with default options
|
48
|
+
Object.extend(this._options, this.options);
|
49
|
+
this.setOptions(options);
|
50
|
+
|
51
|
+
//Create the overlay
|
52
|
+
this.MBoverlay = new Element("div", { id: "MB_overlay", opacity: "0" });
|
53
|
+
|
54
|
+
//Create DOm for the window
|
55
|
+
this.MBwindow = new Element("div", {id: "MB_window", style: "display: none"}).update(
|
56
|
+
this.MBframe = new Element("div", {id: "MB_frame"}).update(
|
57
|
+
this.MBheader = new Element("div", {id: "MB_header"}).update(
|
58
|
+
this.MBcaption = new Element("div", {id: "MB_caption"})
|
59
|
+
)
|
60
|
+
)
|
61
|
+
);
|
62
|
+
this.MBclose = new Element("a", {id: "MB_close", title: this.options.closeString, href: "#"}).update("<span>" + this.options.closeValue + "</span>");
|
63
|
+
this.MBheader.insert({'bottom':this.MBclose});
|
64
|
+
|
65
|
+
this.MBcontent = new Element("div", {id: "MB_content"}).update(
|
66
|
+
this.MBloading = new Element("div", {id: "MB_loading"}).update(this.options.loadingString)
|
67
|
+
);
|
68
|
+
this.MBframe.insert({'bottom':this.MBcontent});
|
69
|
+
|
70
|
+
// Inserting into DOM. If parameter set and form element have been found will inject into it. Otherwise will inject into body as topmost element.
|
71
|
+
// Be sure to set padding and marging to null via CSS for both body and (in case of asp.net) form elements.
|
72
|
+
var injectToEl = this.options.aspnet ? $(document.body).down('form') : $(document.body);
|
73
|
+
injectToEl.insert({'top':this.MBwindow});
|
74
|
+
injectToEl.insert({'top':this.MBoverlay});
|
75
|
+
|
76
|
+
// Initial scrolling position of the window. To be used for remove scrolling effect during ModalBox appearing
|
77
|
+
this.initScrollX = window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft;
|
78
|
+
this.initScrollY = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
|
79
|
+
|
80
|
+
//Adding event observers
|
81
|
+
this.hideObserver = this._hide.bindAsEventListener(this);
|
82
|
+
this.kbdObserver = this._kbdHandler.bindAsEventListener(this);
|
83
|
+
this._initObservers();
|
84
|
+
|
85
|
+
this.initialized = true; // Mark as initialized
|
86
|
+
},
|
87
|
+
|
88
|
+
show: function(content, options) {
|
89
|
+
if(!this.initialized) this._init(options); // Check for is already initialized
|
90
|
+
|
91
|
+
this.content = content;
|
92
|
+
this.setOptions(options);
|
93
|
+
|
94
|
+
if(this.options.title) // Updating title of the MB
|
95
|
+
$(this.MBcaption).update(this.options.title);
|
96
|
+
else { // If title isn't given, the header will not displayed
|
97
|
+
$(this.MBheader).hide();
|
98
|
+
$(this.MBcaption).hide();
|
99
|
+
}
|
100
|
+
|
101
|
+
if(this.MBwindow.style.display == "none") { // First modal box appearing
|
102
|
+
this._appear();
|
103
|
+
this.event("onShow"); // Passing onShow callback
|
104
|
+
}
|
105
|
+
else { // If MB already on the screen, update it
|
106
|
+
this._update();
|
107
|
+
this.event("onUpdate"); // Passing onUpdate callback
|
108
|
+
}
|
109
|
+
},
|
110
|
+
|
111
|
+
hide: function(options) { // External hide method to use from external HTML and JS
|
112
|
+
if(this.initialized) {
|
113
|
+
// Reading for options/callbacks except if event given as a pararmeter
|
114
|
+
if(options && typeof options.element != 'function') Object.extend(this.options, options);
|
115
|
+
// Passing beforeHide callback
|
116
|
+
this.event("beforeHide");
|
117
|
+
if(this.options.transitions)
|
118
|
+
Effect.SlideUp(this.MBwindow, { duration: this.options.slideUpDuration, transition: Effect.Transitions.sinoidal, afterFinish: this._deinit.bind(this) } );
|
119
|
+
else {
|
120
|
+
$(this.MBwindow).hide();
|
121
|
+
this._deinit();
|
122
|
+
}
|
123
|
+
} else throw("Modalbox is not initialized.");
|
124
|
+
},
|
125
|
+
|
126
|
+
_hide: function(event) { // Internal hide method to use with overlay and close link
|
127
|
+
event.stop(); // Stop event propaganation for link elements
|
128
|
+
/* Then clicked on overlay we'll check the option and in case of overlayClose == false we'll break hiding execution [Fix for #139] */
|
129
|
+
if(event.element().id == 'MB_overlay' && !this.options.overlayClose) return false;
|
130
|
+
this.hide();
|
131
|
+
},
|
132
|
+
|
133
|
+
alert: function(message){
|
134
|
+
var html = '<div class="MB_alert"><p>' + message + '</p><input type="button" onclick="Modalbox.hide()" value="OK" /></div>';
|
135
|
+
Modalbox.show(html, {title: 'Alert: ' + document.title, width: 300});
|
136
|
+
},
|
137
|
+
|
138
|
+
_appear: function() { // First appearing of MB
|
139
|
+
if(Prototype.Browser.IE && !navigator.appVersion.match(/\b7.0\b/)) { // Preparing IE 6 for showing modalbox
|
140
|
+
window.scrollTo(0,0);
|
141
|
+
this._prepareIE("100%", "hidden");
|
142
|
+
}
|
143
|
+
this._setWidth();
|
144
|
+
this._setPosition();
|
145
|
+
if(this.options.transitions) {
|
146
|
+
$(this.MBoverlay).setStyle({opacity: 0});
|
147
|
+
new Effect.Fade(this.MBoverlay, {
|
148
|
+
from: 0,
|
149
|
+
to: this.options.overlayOpacity,
|
150
|
+
duration: this.options.overlayDuration,
|
151
|
+
afterFinish: function() {
|
152
|
+
new Effect.SlideDown(this.MBwindow, {
|
153
|
+
duration: this.options.slideDownDuration,
|
154
|
+
transition: Effect.Transitions.sinoidal,
|
155
|
+
afterFinish: function(){
|
156
|
+
this._setPosition();
|
157
|
+
this.loadContent();
|
158
|
+
}.bind(this)
|
159
|
+
});
|
160
|
+
}.bind(this)
|
161
|
+
});
|
162
|
+
} else {
|
163
|
+
$(this.MBoverlay).setStyle({opacity: this.options.overlayOpacity});
|
164
|
+
$(this.MBwindow).show();
|
165
|
+
this._setPosition();
|
166
|
+
this.loadContent();
|
167
|
+
}
|
168
|
+
this._setWidthAndPosition = this._setWidthAndPosition.bindAsEventListener(this);
|
169
|
+
Event.observe(window, "resize", this._setWidthAndPosition);
|
170
|
+
},
|
171
|
+
|
172
|
+
resize: function(byWidth, byHeight, options) { // Change size of MB without loading content
|
173
|
+
var wHeight = $(this.MBwindow).getHeight();
|
174
|
+
var wWidth = $(this.MBwindow).getWidth();
|
175
|
+
var hHeight = $(this.MBheader).getHeight();
|
176
|
+
var cHeight = $(this.MBcontent).getHeight();
|
177
|
+
var newHeight = ((wHeight - hHeight + byHeight) < cHeight) ? (cHeight + hHeight - wHeight) : byHeight;
|
178
|
+
if(options) this.setOptions(options); // Passing callbacks
|
179
|
+
if(this.options.transitions) {
|
180
|
+
new Effect.ScaleBy(this.MBwindow, byWidth, newHeight, {
|
181
|
+
duration: this.options.resizeDuration,
|
182
|
+
afterFinish: function() {
|
183
|
+
this.event("_afterResize"); // Passing internal callback
|
184
|
+
this.event("afterResize"); // Passing callback
|
185
|
+
}.bind(this)
|
186
|
+
});
|
187
|
+
} else {
|
188
|
+
this.MBwindow.setStyle({width: wWidth + byWidth + "px", height: wHeight + newHeight + "px"});
|
189
|
+
setTimeout(function() {
|
190
|
+
this.event("_afterResize"); // Passing internal callback
|
191
|
+
this.event("afterResize"); // Passing callback
|
192
|
+
}.bind(this), 1);
|
193
|
+
|
194
|
+
}
|
195
|
+
|
196
|
+
},
|
197
|
+
|
198
|
+
resizeToContent: function(options){
|
199
|
+
|
200
|
+
// Resizes the modalbox window to the actual content height.
|
201
|
+
// This might be useful to resize modalbox after some content modifications which were changed ccontent height.
|
202
|
+
|
203
|
+
var byHeight = this.options.height - this.MBwindow.offsetHeight;
|
204
|
+
if(byHeight != 0) {
|
205
|
+
if(options) this.setOptions(options); // Passing callbacks
|
206
|
+
Modalbox.resize(0, byHeight);
|
207
|
+
}
|
208
|
+
},
|
209
|
+
|
210
|
+
resizeToInclude: function(element, options){
|
211
|
+
|
212
|
+
// Resizes the modalbox window to the camulative height of element. Calculations are using CSS properties for margins and border.
|
213
|
+
// This method might be useful to resize modalbox before including or updating content.
|
214
|
+
|
215
|
+
var el = $(element);
|
216
|
+
var elHeight = el.getHeight() + parseInt(el.getStyle('margin-top')) + parseInt(el.getStyle('margin-bottom')) + parseInt(el.getStyle('border-top-width')) + parseInt(el.getStyle('border-bottom-width'));
|
217
|
+
if(elHeight > 0) {
|
218
|
+
if(options) this.setOptions(options); // Passing callbacks
|
219
|
+
Modalbox.resize(0, elHeight);
|
220
|
+
}
|
221
|
+
},
|
222
|
+
|
223
|
+
_update: function() { // Updating MB in case of wizards
|
224
|
+
$(this.MBcontent).update("");
|
225
|
+
this.MBcontent.appendChild(this.MBloading);
|
226
|
+
$(this.MBloading).update(this.options.loadingString);
|
227
|
+
this.currentDims = [this.MBwindow.offsetWidth, this.MBwindow.offsetHeight];
|
228
|
+
Modalbox.resize((this.options.width - this.currentDims[0]), (this.options.height - this.currentDims[1]), {_afterResize: this._loadAfterResize.bind(this) });
|
229
|
+
},
|
230
|
+
|
231
|
+
loadContent: function () {
|
232
|
+
if(this.event("beforeLoad") != false) { // If callback passed false, skip loading of the content
|
233
|
+
if(typeof this.content == 'string') {
|
234
|
+
var htmlRegExp = new RegExp(/<\/?[^>]+>/gi);
|
235
|
+
if(htmlRegExp.test(this.content)) { // Plain HTML given as a parameter
|
236
|
+
this._insertContent(this.content.stripScripts());
|
237
|
+
this._putContent(function(){
|
238
|
+
this.content.extractScripts().map(function(script) {
|
239
|
+
return eval(script.replace("<!--", "").replace("// -->", ""));
|
240
|
+
}.bind(window));
|
241
|
+
}.bind(this));
|
242
|
+
} else // URL given as a parameter. We'll request it via Ajax
|
243
|
+
new Ajax.Request( this.content, { method: this.options.method.toLowerCase(), parameters: this.options.params,
|
244
|
+
onSuccess: function(transport) {
|
245
|
+
var response = new String(transport.responseText);
|
246
|
+
this._insertContent(transport.responseText.stripScripts());
|
247
|
+
this._putContent(function(){
|
248
|
+
response.extractScripts().map(function(script) {
|
249
|
+
return eval(script.replace("<!--", "").replace("// -->", ""));
|
250
|
+
}.bind(window));
|
251
|
+
});
|
252
|
+
}.bind(this),
|
253
|
+
onException: function(instance, exception){
|
254
|
+
Modalbox.hide();
|
255
|
+
throw('Modalbox Loading Error: ' + exception);
|
256
|
+
}
|
257
|
+
});
|
258
|
+
|
259
|
+
} else if (typeof this.content == 'object') {// HTML Object is given
|
260
|
+
this._insertContent(this.content);
|
261
|
+
this._putContent();
|
262
|
+
} else {
|
263
|
+
Modalbox.hide();
|
264
|
+
throw('Modalbox Parameters Error: Please specify correct URL or HTML element (plain HTML or object)');
|
265
|
+
}
|
266
|
+
}
|
267
|
+
},
|
268
|
+
|
269
|
+
_insertContent: function(content){
|
270
|
+
$(this.MBcontent).hide().update("");
|
271
|
+
if(typeof content == 'string') {
|
272
|
+
setTimeout(function() { // Hack to disable content flickering in Firefox
|
273
|
+
this.MBcontent.update(content);
|
274
|
+
}.bind(this), 1);
|
275
|
+
} else if (typeof content == 'object') { // HTML Object is given
|
276
|
+
var _htmlObj = content.cloneNode(true); // If node already a part of DOM we'll clone it
|
277
|
+
// If clonable element has ID attribute defined, modifying it to prevent duplicates
|
278
|
+
if(content.id) content.id = "MB_" + content.id;
|
279
|
+
/* Add prefix for IDs on all elements inside the DOM node */
|
280
|
+
$(content).select('*[id]').each(function(el){ el.id = "MB_" + el.id; });
|
281
|
+
this.MBcontent.appendChild(_htmlObj);
|
282
|
+
this.MBcontent.down().show(); // Toggle visibility for hidden nodes
|
283
|
+
if(Prototype.Browser.IE) // Toggling back visibility for hidden selects in IE
|
284
|
+
$$("#MB_content select").invoke('setStyle', {'visibility': ''});
|
285
|
+
}
|
286
|
+
},
|
287
|
+
|
288
|
+
_putContent: function(callback){
|
289
|
+
// Prepare and resize modal box for content
|
290
|
+
if(this.options.height == this._options.height) {
|
291
|
+
setTimeout(function() { // MSIE sometimes doesn't display content correctly
|
292
|
+
Modalbox.resize(0, $(this.MBcontent).getHeight() - $(this.MBwindow).getHeight() + $(this.MBheader).getHeight(), {
|
293
|
+
afterResize: function(){
|
294
|
+
this.MBcontent.show().makePositioned();
|
295
|
+
this.focusableElements = this._findFocusableElements();
|
296
|
+
this._setFocus(); // Setting focus on first 'focusable' element in content (input, select, textarea, link or button)
|
297
|
+
setTimeout(function(){ // MSIE fix
|
298
|
+
if(callback != undefined)
|
299
|
+
callback(); // Executing internal JS from loaded content
|
300
|
+
this.event("afterLoad"); // Passing callback
|
301
|
+
}.bind(this),1);
|
302
|
+
}.bind(this)
|
303
|
+
});
|
304
|
+
}.bind(this), 1);
|
305
|
+
} else { // Height is defined. Creating a scrollable window
|
306
|
+
this._setWidth();
|
307
|
+
this.MBcontent.setStyle({overflow: 'auto', height: $(this.MBwindow).getHeight() - $(this.MBheader).getHeight() - 13 + 'px'});
|
308
|
+
this.MBcontent.show();
|
309
|
+
this.focusableElements = this._findFocusableElements();
|
310
|
+
this._setFocus(); // Setting focus on first 'focusable' element in content (input, select, textarea, link or button)
|
311
|
+
setTimeout(function(){ // MSIE fix
|
312
|
+
if(callback != undefined)
|
313
|
+
callback(); // Executing internal JS from loaded content
|
314
|
+
this.event("afterLoad"); // Passing callback
|
315
|
+
}.bind(this),1);
|
316
|
+
}
|
317
|
+
},
|
318
|
+
|
319
|
+
activate: function(options){
|
320
|
+
this.setOptions(options);
|
321
|
+
this.active = true;
|
322
|
+
$(this.MBclose).observe("click", this.hideObserver);
|
323
|
+
if(this.options.overlayClose)
|
324
|
+
$(this.MBoverlay).observe("click", this.hideObserver);
|
325
|
+
$(this.MBclose).show();
|
326
|
+
if(this.options.transitions && this.options.inactiveFade)
|
327
|
+
new Effect.Appear(this.MBwindow, {duration: this.options.slideUpDuration});
|
328
|
+
},
|
329
|
+
|
330
|
+
deactivate: function(options) {
|
331
|
+
this.setOptions(options);
|
332
|
+
this.active = false;
|
333
|
+
$(this.MBclose).stopObserving("click", this.hideObserver);
|
334
|
+
if(this.options.overlayClose)
|
335
|
+
$(this.MBoverlay).stopObserving("click", this.hideObserver);
|
336
|
+
$(this.MBclose).hide();
|
337
|
+
if(this.options.transitions && this.options.inactiveFade)
|
338
|
+
new Effect.Fade(this.MBwindow, {duration: this.options.slideUpDuration, to: .75});
|
339
|
+
},
|
340
|
+
|
341
|
+
_initObservers: function(){
|
342
|
+
$(this.MBclose).observe("click", this.hideObserver);
|
343
|
+
if(this.options.overlayClose)
|
344
|
+
$(this.MBoverlay).observe("click", this.hideObserver);
|
345
|
+
if(Prototype.Browser.IE)
|
346
|
+
Event.observe(document, "keydown", this.kbdObserver);
|
347
|
+
else
|
348
|
+
Event.observe(document, "keypress", this.kbdObserver);
|
349
|
+
},
|
350
|
+
|
351
|
+
_removeObservers: function(){
|
352
|
+
$(this.MBclose).stopObserving("click", this.hideObserver);
|
353
|
+
if(this.options.overlayClose)
|
354
|
+
$(this.MBoverlay).stopObserving("click", this.hideObserver);
|
355
|
+
if(Prototype.Browser.IE)
|
356
|
+
Event.stopObserving(document, "keydown", this.kbdObserver);
|
357
|
+
else
|
358
|
+
Event.stopObserving(document, "keypress", this.kbdObserver);
|
359
|
+
},
|
360
|
+
|
361
|
+
_loadAfterResize: function() {
|
362
|
+
this._setWidth();
|
363
|
+
this._setPosition();
|
364
|
+
this.loadContent();
|
365
|
+
},
|
366
|
+
|
367
|
+
_setFocus: function() {
|
368
|
+
/* Setting focus to the first 'focusable' element which is one with tabindex = 1 or the first in the form loaded. */
|
369
|
+
if(this.focusableElements.length > 0 && this.options.autoFocusing == true) {
|
370
|
+
var firstEl = this.focusableElements.find(function (el){
|
371
|
+
return el.tabIndex == 1;
|
372
|
+
}) || this.focusableElements.first();
|
373
|
+
this.currFocused = this.focusableElements.toArray().indexOf(firstEl);
|
374
|
+
firstEl.focus(); // Focus on first focusable element except close button
|
375
|
+
} else if($(this.MBclose).visible())
|
376
|
+
$(this.MBclose).focus(); // If no focusable elements exist focus on close button
|
377
|
+
},
|
378
|
+
|
379
|
+
_findFocusableElements: function(){ // Collect form elements or links from MB content
|
380
|
+
this.MBcontent.select('input:not([type~=hidden]), select, textarea, button, a[href]').invoke('addClassName', 'MB_focusable');
|
381
|
+
return this.MBcontent.select('.MB_focusable');
|
382
|
+
},
|
383
|
+
|
384
|
+
_kbdHandler: function(event) {
|
385
|
+
var node = event.element();
|
386
|
+
switch(event.keyCode) {
|
387
|
+
case Event.KEY_TAB:
|
388
|
+
event.stop();
|
389
|
+
|
390
|
+
/* Switching currFocused to the element which was focused by mouse instead of TAB-key. Fix for #134 */
|
391
|
+
if(node != this.focusableElements[this.currFocused])
|
392
|
+
this.currFocused = this.focusableElements.toArray().indexOf(node);
|
393
|
+
|
394
|
+
if(!event.shiftKey) { //Focusing in direct order
|
395
|
+
if(this.currFocused == this.focusableElements.length - 1) {
|
396
|
+
this.focusableElements.first().focus();
|
397
|
+
this.currFocused = 0;
|
398
|
+
} else {
|
399
|
+
this.currFocused++;
|
400
|
+
this.focusableElements[this.currFocused].focus();
|
401
|
+
}
|
402
|
+
} else { // Shift key is pressed. Focusing in reverse order
|
403
|
+
if(this.currFocused == 0) {
|
404
|
+
this.focusableElements.last().focus();
|
405
|
+
this.currFocused = this.focusableElements.length - 1;
|
406
|
+
} else {
|
407
|
+
this.currFocused--;
|
408
|
+
this.focusableElements[this.currFocused].focus();
|
409
|
+
}
|
410
|
+
}
|
411
|
+
break;
|
412
|
+
case Event.KEY_ESC:
|
413
|
+
if(this.active) this._hide(event);
|
414
|
+
break;
|
415
|
+
case 32:
|
416
|
+
this._preventScroll(event);
|
417
|
+
break;
|
418
|
+
case 0: // For Gecko browsers compatibility
|
419
|
+
if(event.which == 32) this._preventScroll(event);
|
420
|
+
break;
|
421
|
+
case Event.KEY_UP:
|
422
|
+
case Event.KEY_DOWN:
|
423
|
+
case Event.KEY_PAGEDOWN:
|
424
|
+
case Event.KEY_PAGEUP:
|
425
|
+
case Event.KEY_HOME:
|
426
|
+
case Event.KEY_END:
|
427
|
+
// Safari operates in slightly different way. This realization is still buggy in Safari.
|
428
|
+
if(Prototype.Browser.WebKit && !["textarea", "select"].include(node.tagName.toLowerCase()))
|
429
|
+
event.stop();
|
430
|
+
else if( (node.tagName.toLowerCase() == "input" && ["submit", "button"].include(node.type)) || (node.tagName.toLowerCase() == "a") )
|
431
|
+
event.stop();
|
432
|
+
break;
|
433
|
+
}
|
434
|
+
},
|
435
|
+
|
436
|
+
_preventScroll: function(event) { // Disabling scrolling by "space" key
|
437
|
+
if(!["input", "textarea", "select", "button"].include(event.element().tagName.toLowerCase()))
|
438
|
+
event.stop();
|
439
|
+
},
|
440
|
+
|
441
|
+
_deinit: function()
|
442
|
+
{
|
443
|
+
this._removeObservers();
|
444
|
+
Event.stopObserving(window, "resize", this._setWidthAndPosition );
|
445
|
+
if(this.options.transitions) {
|
446
|
+
Effect.toggle(this.MBoverlay, 'appear', {duration: this.options.overlayDuration, afterFinish: this._removeElements.bind(this) });
|
447
|
+
} else {
|
448
|
+
this.MBoverlay.hide();
|
449
|
+
this._removeElements();
|
450
|
+
}
|
451
|
+
$(this.MBcontent).setStyle({overflow: '', height: ''});
|
452
|
+
},
|
453
|
+
|
454
|
+
_removeElements: function () {
|
455
|
+
$(this.MBoverlay).remove();
|
456
|
+
$(this.MBwindow).remove();
|
457
|
+
if(Prototype.Browser.IE && !navigator.appVersion.match(/\b7.0\b/)) {
|
458
|
+
this._prepareIE("", ""); // If set to auto MSIE will show horizontal scrolling
|
459
|
+
window.scrollTo(this.initScrollX, this.initScrollY);
|
460
|
+
}
|
461
|
+
|
462
|
+
/* Replacing prefixes 'MB_' in IDs for the original content */
|
463
|
+
if(typeof this.content == 'object') {
|
464
|
+
if(this.content.id && this.content.id.match(/MB_/)) {
|
465
|
+
this.content.id = this.content.id.replace(/MB_/, "");
|
466
|
+
}
|
467
|
+
this.content.select('*[id]').each(function(el){ el.id = el.id.replace(/MB_/, ""); });
|
468
|
+
}
|
469
|
+
/* Initialized will be set to false */
|
470
|
+
this.initialized = false;
|
471
|
+
this.event("afterHide"); // Passing afterHide callback
|
472
|
+
this.setOptions(this._options); //Settings options object into intial state
|
473
|
+
},
|
474
|
+
|
475
|
+
_setWidth: function () { //Set size
|
476
|
+
$(this.MBwindow).setStyle({width: this.options.width + "px", height: this.options.height + "px"});
|
477
|
+
},
|
478
|
+
|
479
|
+
_setPosition: function () {
|
480
|
+
$(this.MBwindow).setStyle({left: Math.round((Element.getWidth(document.body) - Element.getWidth(this.MBwindow)) / 2 ) + "px"});
|
481
|
+
},
|
482
|
+
|
483
|
+
_setWidthAndPosition: function () {
|
484
|
+
$(this.MBwindow).setStyle({width: this.options.width + "px"});
|
485
|
+
this._setPosition();
|
486
|
+
},
|
487
|
+
|
488
|
+
_getScrollTop: function () { //From: http://www.quirksmode.org/js/doctypes.html
|
489
|
+
var theTop;
|
490
|
+
if (document.documentElement && document.documentElement.scrollTop)
|
491
|
+
theTop = document.documentElement.scrollTop;
|
492
|
+
else if (document.body)
|
493
|
+
theTop = document.body.scrollTop;
|
494
|
+
return theTop;
|
495
|
+
},
|
496
|
+
_prepareIE: function(height, overflow){
|
497
|
+
$$('html, body').invoke('setStyle', {width: height, height: height, overflow: overflow}); // IE requires width and height set to 100% and overflow hidden
|
498
|
+
$$("select").invoke('setStyle', {'visibility': overflow}); // Toggle visibility for all selects in the common document
|
499
|
+
},
|
500
|
+
event: function(eventName) {
|
501
|
+
if(this.options[eventName]) {
|
502
|
+
var returnValue = this.options[eventName](); // Executing callback
|
503
|
+
this.options[eventName] = null; // Removing callback after execution
|
504
|
+
if(returnValue != undefined)
|
505
|
+
return returnValue;
|
506
|
+
else
|
507
|
+
return true;
|
508
|
+
}
|
509
|
+
return true;
|
510
|
+
}
|
511
|
+
};
|
512
|
+
|
513
|
+
Object.extend(Modalbox, Modalbox.Methods);
|
514
|
+
|
515
|
+
if(Modalbox.overrideAlert) window.alert = Modalbox.alert;
|
516
|
+
|
517
|
+
Effect.ScaleBy = Class.create();
|
518
|
+
Object.extend(Object.extend(Effect.ScaleBy.prototype, Effect.Base.prototype), {
|
519
|
+
initialize: function(element, byWidth, byHeight, options) {
|
520
|
+
this.element = $(element)
|
521
|
+
var options = Object.extend({
|
522
|
+
scaleFromTop: true,
|
523
|
+
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
|
524
|
+
scaleByWidth: byWidth,
|
525
|
+
scaleByHeight: byHeight
|
526
|
+
}, arguments[3] || {});
|
527
|
+
this.start(options);
|
528
|
+
},
|
529
|
+
setup: function() {
|
530
|
+
this.elementPositioning = this.element.getStyle('position');
|
531
|
+
|
532
|
+
this.originalTop = this.element.offsetTop;
|
533
|
+
this.originalLeft = this.element.offsetLeft;
|
534
|
+
|
535
|
+
this.dims = null;
|
536
|
+
if(this.options.scaleMode=='box')
|
537
|
+
this.dims = [this.element.offsetHeight, this.element.offsetWidth];
|
538
|
+
if(/^content/.test(this.options.scaleMode))
|
539
|
+
this.dims = [this.element.scrollHeight, this.element.scrollWidth];
|
540
|
+
if(!this.dims)
|
541
|
+
this.dims = [this.options.scaleMode.originalHeight,
|
542
|
+
this.options.scaleMode.originalWidth];
|
543
|
+
|
544
|
+
this.deltaY = this.options.scaleByHeight;
|
545
|
+
this.deltaX = this.options.scaleByWidth;
|
546
|
+
},
|
547
|
+
update: function(position) {
|
548
|
+
var currentHeight = this.dims[0] + (this.deltaY * position);
|
549
|
+
var currentWidth = this.dims[1] + (this.deltaX * position);
|
550
|
+
|
551
|
+
currentHeight = (currentHeight > 0) ? currentHeight : 0;
|
552
|
+
currentWidth = (currentWidth > 0) ? currentWidth : 0;
|
553
|
+
|
554
|
+
this.setDimensions(currentHeight, currentWidth);
|
555
|
+
},
|
556
|
+
|
557
|
+
setDimensions: function(height, width) {
|
558
|
+
var d = {};
|
559
|
+
d.width = width + 'px';
|
560
|
+
d.height = height + 'px';
|
561
|
+
|
562
|
+
var topd = Math.round((height - this.dims[0])/2);
|
563
|
+
var leftd = Math.round((width - this.dims[1])/2);
|
564
|
+
if(this.elementPositioning == 'absolute' || this.elementPositioning == 'fixed') {
|
565
|
+
if(!this.options.scaleFromTop) d.top = this.originalTop-topd + 'px';
|
566
|
+
d.left = this.originalLeft-leftd + 'px';
|
567
|
+
} else {
|
568
|
+
if(!this.options.scaleFromTop) d.top = -topd + 'px';
|
569
|
+
d.left = -leftd + 'px';
|
570
|
+
}
|
571
|
+
this.element.setStyle(d);
|
572
|
+
}
|
573
|
+
});
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#MB_overlay {
|
2
|
+
position: absolute;
|
3
|
+
margin: auto;
|
4
|
+
top: 0; left: 0;
|
5
|
+
width: 100%; height: 100%;
|
6
|
+
z-index: 9999;
|
7
|
+
background-color: #000!important;
|
8
|
+
}
|
9
|
+
#MB_overlay[id] { position: fixed; }
|
10
|
+
|
11
|
+
#MB_window {
|
12
|
+
position: absolute;
|
13
|
+
top: 0;
|
14
|
+
border: 0 solid;
|
15
|
+
text-align: left;
|
16
|
+
z-index: 10000;
|
17
|
+
}
|
18
|
+
#MB_window[id] { position: fixed!important; }
|
19
|
+
|
20
|
+
#MB_frame {
|
21
|
+
position: relative;
|
22
|
+
background-color: #EFEFEF;
|
23
|
+
height: 100%;
|
24
|
+
}
|
25
|
+
|
26
|
+
#MB_header {
|
27
|
+
margin: 0;
|
28
|
+
padding: 0;
|
29
|
+
}
|
30
|
+
|
31
|
+
#MB_content {
|
32
|
+
padding: 6px .75em;
|
33
|
+
overflow: auto;
|
34
|
+
}
|
35
|
+
|
36
|
+
#MB_caption {
|
37
|
+
font: bold 100% "Lucida Grande", Arial, sans-serif;
|
38
|
+
text-shadow: #FFF 0 1px 0;
|
39
|
+
padding: .5em 2em .5em .75em;
|
40
|
+
margin: 0;
|
41
|
+
text-align: left;
|
42
|
+
}
|
43
|
+
|
44
|
+
#MB_close {
|
45
|
+
display: block;
|
46
|
+
position: absolute;
|
47
|
+
right: 5px; top: 4px;
|
48
|
+
padding: 2px 3px;
|
49
|
+
font-weight: bold;
|
50
|
+
text-decoration: none;
|
51
|
+
font-size: 13px;
|
52
|
+
}
|
53
|
+
#MB_close:hover {
|
54
|
+
background: transparent;
|
55
|
+
}
|
56
|
+
|
57
|
+
#MB_loading {
|
58
|
+
padding: 1.5em;
|
59
|
+
text-indent: -10000px;
|
60
|
+
background: transparent url(spinner.gif) 50% 0 no-repeat;
|
61
|
+
}
|
62
|
+
|
63
|
+
/* Color scheme */
|
64
|
+
#MB_frame {
|
65
|
+
padding-bottom: 7px;
|
66
|
+
-webkit-border-radius: 7px;
|
67
|
+
-moz-border-radius: 7px;
|
68
|
+
border-radius: 7px;
|
69
|
+
}
|
70
|
+
#MB_window {
|
71
|
+
background-color: #EFEFEF;
|
72
|
+
color: #000;
|
73
|
+
-webkit-box-shadow: 0 8px 64px #000;
|
74
|
+
-moz-box-shadow: 0 0 64px #000;
|
75
|
+
box-shadow: 0 0 64px #000;
|
76
|
+
|
77
|
+
-webkit-border-radius: 7px;
|
78
|
+
-moz-border-radius: 7px;
|
79
|
+
border-radius: 7px;
|
80
|
+
}
|
81
|
+
#MB_content { border-top: 1px solid #F9F9F9; }
|
82
|
+
#MB_header {
|
83
|
+
background-color: #DDD;
|
84
|
+
border-bottom: 1px solid #CCC;
|
85
|
+
}
|
86
|
+
#MB_caption { color: #000 }
|
87
|
+
#MB_close { color: #777 }
|
88
|
+
#MB_close:hover { color: #000 }
|
89
|
+
|
90
|
+
|
91
|
+
/* Alert message */
|
92
|
+
.MB_alert {
|
93
|
+
margin: 10px 0;
|
94
|
+
text-align: center;
|
95
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "image_picker"
|
3
|
+
s.version = "0.5"
|
4
|
+
s.date = "2008-10-23"
|
5
|
+
s.summary = "A simple, customizable image browser."
|
6
|
+
s.email = "pelargir@gmail.com"
|
7
|
+
s.homepage = "http://github.com/pelargir/image_picker"
|
8
|
+
s.description = "A simple, customizable image browser."
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.authors = ["Matthew Bass"]
|
11
|
+
s.files = [
|
12
|
+
"CHANGELOG",
|
13
|
+
"files/public/images/no_image.jpg",
|
14
|
+
"files/public/images/spinner.gif",
|
15
|
+
"files/public/javascripts/image_picker.js",
|
16
|
+
"files/public/javascripts/modalbox.js",
|
17
|
+
"files/public/stylesheets/modalbox.css",
|
18
|
+
"init.rb",
|
19
|
+
"install.rb",
|
20
|
+
"lib/image_picker.rb",
|
21
|
+
"lib/image_picker/controller.rb",
|
22
|
+
"lib/image_picker/link_renderer.rb",
|
23
|
+
"MIT-LICENSE",
|
24
|
+
"Rakefile",
|
25
|
+
"README",
|
26
|
+
"tasks/image_picker.rake",
|
27
|
+
"templates/open_picker.html.erb",
|
28
|
+
"image_picker.gemspec"
|
29
|
+
]
|
30
|
+
s.rdoc_options = ["--main", "README"]
|
31
|
+
s.extra_rdoc_files = ["README"]
|
32
|
+
end
|
data/init.rb
ADDED
data/install.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
begin
|
4
|
+
puts "=========================================================="
|
5
|
+
puts "Attempting to copy required files into your application..."
|
6
|
+
puts "=========================================================="
|
7
|
+
RAKE_FILE = File.join(File.dirname(__FILE__), '/tasks/image_picker.rake')
|
8
|
+
load RAKE_FILE
|
9
|
+
|
10
|
+
Rake::Task['image_picker:install_files'].invoke
|
11
|
+
puts "=========================================================="
|
12
|
+
puts "Success!"
|
13
|
+
puts "=========================================================="
|
14
|
+
rescue Exception => ex
|
15
|
+
puts "FAILED TO COPY FILES DURING INSTALL. PLEASE RUN rake image_picker:install_files."
|
16
|
+
puts "EXCEPTION: #{ex}"
|
17
|
+
end
|
data/lib/image_picker.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module ImagePicker
|
2
|
+
def image_picker(field)
|
3
|
+
url = url_for :action => "open_picker"
|
4
|
+
html = stylesheet_link_tag "modalbox"
|
5
|
+
html += javascript_include_tag :defaults, "image_picker", "modalbox"
|
6
|
+
html += link_to_function image_tag("no_image.jpg", :id => field), "ImagePicker.open_picker({field:'#{field}', url:'#{url}'})"
|
7
|
+
html += hidden_field_tag "#{field}_id"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
ActionView::Base.send :include, ImagePicker
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ImagePicker
|
2
|
+
module Controller
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def image_picker(options={})
|
9
|
+
define_method "open_picker" do
|
10
|
+
model = options.delete(:model)
|
11
|
+
@field = params[:field]
|
12
|
+
@images = defined?(WillPaginate) ? model.paginate(options.merge(:page => params[:page])) : model.all(options)
|
13
|
+
render :file => "#{RAILS_ROOT}/vendor/plugins/image_picker/templates/open_picker.html.erb"
|
14
|
+
end
|
15
|
+
|
16
|
+
define_method "pick" do
|
17
|
+
image = Image.find(params[:id])
|
18
|
+
field = params[:field]
|
19
|
+
render :update do |page|
|
20
|
+
page.call "parent.ImagePicker.pick", field, image.id, image.title, image.thumbnail
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
ActionController::Base.send :include, ImagePicker::Controller
|
@@ -0,0 +1,9 @@
|
|
1
|
+
if defined?(WillPaginate)
|
2
|
+
module ImagePicker
|
3
|
+
class LinkRenderer < WillPaginate::LinkRenderer
|
4
|
+
def page_link(page, text, attributes = {})
|
5
|
+
@template.link_to_function text, "ImagePicker.open_picker({field:$('target_field').value, page:'#{page}', terms:$('terms').value});"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'find'
|
2
|
+
|
3
|
+
module ImagePicker
|
4
|
+
class Assets
|
5
|
+
@source = File.expand_path(File.join(File.dirname(__FILE__), '..', 'files'))
|
6
|
+
@destination = RAILS_ROOT
|
7
|
+
class << self
|
8
|
+
attr_accessor :source, :destination
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.install
|
12
|
+
paths = []
|
13
|
+
Find.find(source) do |path|
|
14
|
+
Find.prune if path =~ /\/\..+/
|
15
|
+
Find.prune if path =~ /CVS/
|
16
|
+
paths << path
|
17
|
+
end
|
18
|
+
paths.each do |path|
|
19
|
+
dest_path = path.gsub(source, destination)
|
20
|
+
if File.directory?(path)
|
21
|
+
FileUtils.mkdir_p(dest_path) unless File.exists?(dest_path)
|
22
|
+
else
|
23
|
+
FileUtils.cp(path, dest_path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
rescue Exception => e
|
27
|
+
puts "Error trying to copy files: #{e.inspect}"
|
28
|
+
raise e
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
namespace :image_picker do
|
35
|
+
desc "Install files required by image_picker"
|
36
|
+
task :install_files do
|
37
|
+
ImagePicker::Assets.install
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<div style="width: 500px">
|
2
|
+
<%= hidden_field_tag :target_field, @field %>
|
3
|
+
<%= hidden_field_tag :default_image, "/images/no_image.jpg" %>
|
4
|
+
|
5
|
+
<div style="float:right">
|
6
|
+
<%= link_to_function "clear image", "ImagePicker.clear($('target_field').value, $('default_image').value);", :id => "clear" %>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<% if defined?(WillPaginate) -%>
|
10
|
+
<div style="text-align:center; clear:both;">
|
11
|
+
<%= will_paginate @images, :renderer => ImagePicker::LinkRenderer %>
|
12
|
+
</div>
|
13
|
+
<% end -%>
|
14
|
+
|
15
|
+
<% if @images.any? -%>
|
16
|
+
<table border="0", cellpadding="10" cellspacing="5">
|
17
|
+
<% @images.in_groups_of(3) do |e| -%>
|
18
|
+
<tr>
|
19
|
+
<% e.compact.each do |i| -%>
|
20
|
+
<td style="text-align:center" valign="top">
|
21
|
+
<%= link_to_remote image_tag(i.thumbnail, :alt => i.title), :url => {:action => "pick", :field => @field, :id => i}, :method => :post %>
|
22
|
+
<br/>
|
23
|
+
<strong><%= i.title %></strong>
|
24
|
+
<% if i.respond_to?(:description) -%>
|
25
|
+
<br/>
|
26
|
+
<%= i.description %>
|
27
|
+
<% end -%>
|
28
|
+
</td>
|
29
|
+
<% end -%>
|
30
|
+
</tr>
|
31
|
+
<% end -%>
|
32
|
+
</table>
|
33
|
+
<% else -%>
|
34
|
+
<div style="margin:10px; text-align:center; font-style:italic;">
|
35
|
+
Nothing found.
|
36
|
+
</div>
|
37
|
+
<% end -%>
|
38
|
+
</div>
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pelargir-image_picker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.5"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew Bass
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-10-23 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A simple, customizable image browser.
|
17
|
+
email: pelargir@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- CHANGELOG
|
26
|
+
- files/public/images/no_image.jpg
|
27
|
+
- files/public/images/spinner.gif
|
28
|
+
- files/public/javascripts/image_picker.js
|
29
|
+
- files/public/javascripts/modalbox.js
|
30
|
+
- files/public/stylesheets/modalbox.css
|
31
|
+
- init.rb
|
32
|
+
- install.rb
|
33
|
+
- lib/image_picker.rb
|
34
|
+
- lib/image_picker/controller.rb
|
35
|
+
- lib/image_picker/link_renderer.rb
|
36
|
+
- MIT-LICENSE
|
37
|
+
- Rakefile
|
38
|
+
- README
|
39
|
+
- tasks/image_picker.rake
|
40
|
+
- templates/open_picker.html.erb
|
41
|
+
- image_picker.gemspec
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/pelargir/image_picker
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --main
|
47
|
+
- README
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.2.0
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: A simple, customizable image browser.
|
69
|
+
test_files: []
|
70
|
+
|