Updating for rails 2.2.2
This commit is contained in:
parent
3a0f4d30cf
commit
62f999cd83
130 changed files with 794 additions and 6760 deletions
|
@ -25,7 +25,7 @@ module Rails
|
|||
end
|
||||
|
||||
def preinitialize
|
||||
load(preinitializer_path) if File.exists?(preinitializer_path)
|
||||
load(preinitializer_path) if File.exist?(preinitializer_path)
|
||||
end
|
||||
|
||||
def preinitializer_path
|
||||
|
@ -43,6 +43,7 @@ module Rails
|
|||
class VendorBoot < Boot
|
||||
def load_initializer
|
||||
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
|
||||
Rails::Initializer.run(:install_gem_spec_stubs)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -66,7 +67,7 @@ module Rails
|
|||
|
||||
class << self
|
||||
def rubygems_version
|
||||
Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
|
||||
Gem::RubyGemsVersion rescue nil
|
||||
end
|
||||
|
||||
def gem_version
|
||||
|
@ -81,19 +82,19 @@ module Rails
|
|||
|
||||
def load_rubygems
|
||||
require 'rubygems'
|
||||
|
||||
unless rubygems_version >= '0.9.4'
|
||||
$stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
||||
min_version = '1.3.1'
|
||||
unless rubygems_version >= min_version
|
||||
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
||||
exit 1
|
||||
end
|
||||
|
||||
rescue LoadError
|
||||
$stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
||||
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
||||
exit 1
|
||||
end
|
||||
|
||||
def parse_gem_version(text)
|
||||
$1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*'([!~<>=]*\s*[\d.]+)'/
|
||||
$1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
ENV['RAILS_ENV'] ||= 'production'
|
||||
|
||||
# Specifies gem version of Rails to use when vendor/rails is not present
|
||||
RAILS_GEM_VERSION = '2.1.2' unless defined? RAILS_GEM_VERSION
|
||||
RAILS_GEM_VERSION = '2.2.2' unless defined? RAILS_GEM_VERSION
|
||||
|
||||
# Set the server URL
|
||||
SERVER_URL = ENV['OSM_SERVER_URL'] || 'www.openstreetmap.org'
|
||||
|
@ -46,7 +46,7 @@ Rails::Initializer.run do |config|
|
|||
# config.gem "bj"
|
||||
# config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
|
||||
# config.gem "aws-s3", :lib => "aws/s3"
|
||||
config.gem 'composite_primary_keys', :version => '1.1.0'
|
||||
config.gem 'composite_primary_keys', :version => '2.2.2'
|
||||
config.gem 'libxml-ruby', :version => '>= 1.1.1', :lib => 'libxml'
|
||||
config.gem 'rmagick', :lib => 'RMagick'
|
||||
|
||||
|
|
146
public/javascripts/controls.js
vendored
146
public/javascripts/controls.js
vendored
|
@ -1,22 +1,22 @@
|
|||
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
||||
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
|
||||
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
||||
// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
|
||||
// Contributors:
|
||||
// Richard Livsey
|
||||
// Rahul Bhargava
|
||||
// Rob Wills
|
||||
//
|
||||
//
|
||||
// script.aculo.us is freely distributable under the terms of an MIT-style license.
|
||||
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
||||
|
||||
// Autocompleter.Base handles all the autocompletion functionality
|
||||
// Autocompleter.Base handles all the autocompletion functionality
|
||||
// that's independent of the data source for autocompletion. This
|
||||
// includes drawing the autocompletion menu, observing keyboard
|
||||
// and mouse events, and similar.
|
||||
//
|
||||
// Specific autocompleters need to provide, at the very least,
|
||||
// Specific autocompleters need to provide, at the very least,
|
||||
// a getUpdatedChoices function that will be invoked every time
|
||||
// the text inside the monitored textbox changes. This method
|
||||
// the text inside the monitored textbox changes. This method
|
||||
// should get the text for which to provide autocompletion by
|
||||
// invoking this.getToken(), NOT by directly accessing
|
||||
// this.element.value. This is to allow incremental tokenized
|
||||
|
@ -30,23 +30,23 @@
|
|||
// will incrementally autocomplete with a comma as the token.
|
||||
// Additionally, ',' in the above example can be replaced with
|
||||
// a token array, e.g. { tokens: [',', '\n'] } which
|
||||
// enables autocompletion on multiple tokens. This is most
|
||||
// useful when one of the tokens is \n (a newline), as it
|
||||
// enables autocompletion on multiple tokens. This is most
|
||||
// useful when one of the tokens is \n (a newline), as it
|
||||
// allows smart autocompletion after linebreaks.
|
||||
|
||||
if(typeof Effect == 'undefined')
|
||||
throw("controls.js requires including script.aculo.us' effects.js library");
|
||||
|
||||
var Autocompleter = { }
|
||||
var Autocompleter = { };
|
||||
Autocompleter.Base = Class.create({
|
||||
baseInitialize: function(element, update, options) {
|
||||
element = $(element)
|
||||
this.element = element;
|
||||
this.update = $(update);
|
||||
this.hasFocus = false;
|
||||
this.changed = false;
|
||||
this.active = false;
|
||||
this.index = 0;
|
||||
element = $(element);
|
||||
this.element = element;
|
||||
this.update = $(update);
|
||||
this.hasFocus = false;
|
||||
this.changed = false;
|
||||
this.active = false;
|
||||
this.index = 0;
|
||||
this.entryCount = 0;
|
||||
this.oldElementValue = this.element.value;
|
||||
|
||||
|
@ -59,28 +59,28 @@ Autocompleter.Base = Class.create({
|
|||
this.options.tokens = this.options.tokens || [];
|
||||
this.options.frequency = this.options.frequency || 0.4;
|
||||
this.options.minChars = this.options.minChars || 1;
|
||||
this.options.onShow = this.options.onShow ||
|
||||
function(element, update){
|
||||
this.options.onShow = this.options.onShow ||
|
||||
function(element, update){
|
||||
if(!update.style.position || update.style.position=='absolute') {
|
||||
update.style.position = 'absolute';
|
||||
Position.clone(element, update, {
|
||||
setHeight: false,
|
||||
setHeight: false,
|
||||
offsetTop: element.offsetHeight
|
||||
});
|
||||
}
|
||||
Effect.Appear(update,{duration:0.15});
|
||||
};
|
||||
this.options.onHide = this.options.onHide ||
|
||||
this.options.onHide = this.options.onHide ||
|
||||
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
||||
|
||||
if(typeof(this.options.tokens) == 'string')
|
||||
if(typeof(this.options.tokens) == 'string')
|
||||
this.options.tokens = new Array(this.options.tokens);
|
||||
// Force carriage returns as token delimiters anyway
|
||||
if (!this.options.tokens.include('\n'))
|
||||
this.options.tokens.push('\n');
|
||||
|
||||
this.observer = null;
|
||||
|
||||
|
||||
this.element.setAttribute('autocomplete','off');
|
||||
|
||||
Element.hide(this.update);
|
||||
|
@ -91,10 +91,10 @@ Autocompleter.Base = Class.create({
|
|||
|
||||
show: function() {
|
||||
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
|
||||
if(!this.iefix &&
|
||||
if(!this.iefix &&
|
||||
(Prototype.Browser.IE) &&
|
||||
(Element.getStyle(this.update, 'position')=='absolute')) {
|
||||
new Insertion.After(this.update,
|
||||
new Insertion.After(this.update,
|
||||
'<iframe id="' + this.update.id + '_iefix" '+
|
||||
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
|
||||
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
|
||||
|
@ -102,7 +102,7 @@ Autocompleter.Base = Class.create({
|
|||
}
|
||||
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
|
||||
},
|
||||
|
||||
|
||||
fixIEOverlapping: function() {
|
||||
Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
|
||||
this.iefix.style.zIndex = 1;
|
||||
|
@ -150,15 +150,15 @@ Autocompleter.Base = Class.create({
|
|||
Event.stop(event);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
|
||||
else
|
||||
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
|
||||
(Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
|
||||
|
||||
this.changed = true;
|
||||
this.hasFocus = true;
|
||||
|
||||
if(this.observer) clearTimeout(this.observer);
|
||||
this.observer =
|
||||
this.observer =
|
||||
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
|
||||
},
|
||||
|
||||
|
@ -170,35 +170,35 @@ Autocompleter.Base = Class.create({
|
|||
|
||||
onHover: function(event) {
|
||||
var element = Event.findElement(event, 'LI');
|
||||
if(this.index != element.autocompleteIndex)
|
||||
if(this.index != element.autocompleteIndex)
|
||||
{
|
||||
this.index = element.autocompleteIndex;
|
||||
this.render();
|
||||
}
|
||||
Event.stop(event);
|
||||
},
|
||||
|
||||
|
||||
onClick: function(event) {
|
||||
var element = Event.findElement(event, 'LI');
|
||||
this.index = element.autocompleteIndex;
|
||||
this.selectEntry();
|
||||
this.hide();
|
||||
},
|
||||
|
||||
|
||||
onBlur: function(event) {
|
||||
// needed to make click events working
|
||||
setTimeout(this.hide.bind(this), 250);
|
||||
this.hasFocus = false;
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if(this.entryCount > 0) {
|
||||
for (var i = 0; i < this.entryCount; i++)
|
||||
this.index==i ?
|
||||
Element.addClassName(this.getEntry(i),"selected") :
|
||||
this.index==i ?
|
||||
Element.addClassName(this.getEntry(i),"selected") :
|
||||
Element.removeClassName(this.getEntry(i),"selected");
|
||||
if(this.hasFocus) {
|
||||
if(this.hasFocus) {
|
||||
this.show();
|
||||
this.active = true;
|
||||
}
|
||||
|
@ -207,27 +207,27 @@ Autocompleter.Base = Class.create({
|
|||
this.hide();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
markPrevious: function() {
|
||||
if(this.index > 0) this.index--
|
||||
if(this.index > 0) this.index--;
|
||||
else this.index = this.entryCount-1;
|
||||
this.getEntry(this.index).scrollIntoView(true);
|
||||
},
|
||||
|
||||
|
||||
markNext: function() {
|
||||
if(this.index < this.entryCount-1) this.index++
|
||||
if(this.index < this.entryCount-1) this.index++;
|
||||
else this.index = 0;
|
||||
this.getEntry(this.index).scrollIntoView(false);
|
||||
},
|
||||
|
||||
|
||||
getEntry: function(index) {
|
||||
return this.update.firstChild.childNodes[index];
|
||||
},
|
||||
|
||||
|
||||
getCurrentEntry: function() {
|
||||
return this.getEntry(this.index);
|
||||
},
|
||||
|
||||
|
||||
selectEntry: function() {
|
||||
this.active = false;
|
||||
this.updateElement(this.getCurrentEntry());
|
||||
|
@ -244,7 +244,7 @@ Autocompleter.Base = Class.create({
|
|||
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
|
||||
} else
|
||||
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
|
||||
|
||||
|
||||
var bounds = this.getTokenBounds();
|
||||
if (bounds[0] != -1) {
|
||||
var newValue = this.element.value.substr(0, bounds[0]);
|
||||
|
@ -257,7 +257,7 @@ Autocompleter.Base = Class.create({
|
|||
}
|
||||
this.oldElementValue = this.element.value;
|
||||
this.element.focus();
|
||||
|
||||
|
||||
if (this.options.afterUpdateElement)
|
||||
this.options.afterUpdateElement(this.element, selectedElement);
|
||||
},
|
||||
|
@ -269,20 +269,20 @@ Autocompleter.Base = Class.create({
|
|||
Element.cleanWhitespace(this.update.down());
|
||||
|
||||
if(this.update.firstChild && this.update.down().childNodes) {
|
||||
this.entryCount =
|
||||
this.entryCount =
|
||||
this.update.down().childNodes.length;
|
||||
for (var i = 0; i < this.entryCount; i++) {
|
||||
var entry = this.getEntry(i);
|
||||
entry.autocompleteIndex = i;
|
||||
this.addObservers(entry);
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
this.entryCount = 0;
|
||||
}
|
||||
|
||||
this.stopIndicator();
|
||||
this.index = 0;
|
||||
|
||||
|
||||
if(this.entryCount==1 && this.options.autoSelect) {
|
||||
this.selectEntry();
|
||||
this.hide();
|
||||
|
@ -298,7 +298,7 @@ Autocompleter.Base = Class.create({
|
|||
},
|
||||
|
||||
onObserverEvent: function() {
|
||||
this.changed = false;
|
||||
this.changed = false;
|
||||
this.tokenBounds = null;
|
||||
if(this.getToken().length>=this.options.minChars) {
|
||||
this.getUpdatedChoices();
|
||||
|
@ -351,16 +351,16 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {
|
|||
|
||||
getUpdatedChoices: function() {
|
||||
this.startIndicator();
|
||||
|
||||
var entry = encodeURIComponent(this.options.paramName) + '=' +
|
||||
|
||||
var entry = encodeURIComponent(this.options.paramName) + '=' +
|
||||
encodeURIComponent(this.getToken());
|
||||
|
||||
this.options.parameters = this.options.callback ?
|
||||
this.options.callback(this.element, entry) : entry;
|
||||
|
||||
if(this.options.defaultParams)
|
||||
if(this.options.defaultParams)
|
||||
this.options.parameters += '&' + this.options.defaultParams;
|
||||
|
||||
|
||||
new Ajax.Request(this.url, this.options);
|
||||
},
|
||||
|
||||
|
@ -382,7 +382,7 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {
|
|||
// - choices - How many autocompletion choices to offer
|
||||
//
|
||||
// - partialSearch - If false, the autocompleter will match entered
|
||||
// text only at the beginning of strings in the
|
||||
// text only at the beginning of strings in the
|
||||
// autocomplete array. Defaults to true, which will
|
||||
// match text at the beginning of any *word* in the
|
||||
// strings in the autocomplete array. If you want to
|
||||
|
@ -399,7 +399,7 @@ Ajax.Autocompleter = Class.create(Autocompleter.Base, {
|
|||
// - ignoreCase - Whether to ignore case when autocompleting.
|
||||
// Defaults to true.
|
||||
//
|
||||
// It's possible to pass in a custom function as the 'selector'
|
||||
// It's possible to pass in a custom function as the 'selector'
|
||||
// option, if you prefer to write your own autocompletion logic.
|
||||
// In that case, the other options above will not apply unless
|
||||
// you support them.
|
||||
|
@ -427,20 +427,20 @@ Autocompleter.Local = Class.create(Autocompleter.Base, {
|
|||
var entry = instance.getToken();
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < instance.options.array.length &&
|
||||
ret.length < instance.options.choices ; i++) {
|
||||
for (var i = 0; i < instance.options.array.length &&
|
||||
ret.length < instance.options.choices ; i++) {
|
||||
|
||||
var elem = instance.options.array[i];
|
||||
var foundPos = instance.options.ignoreCase ?
|
||||
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
||||
var foundPos = instance.options.ignoreCase ?
|
||||
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
||||
elem.indexOf(entry);
|
||||
|
||||
while (foundPos != -1) {
|
||||
if (foundPos == 0 && elem.length != entry.length) {
|
||||
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
||||
if (foundPos == 0 && elem.length != entry.length) {
|
||||
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
||||
elem.substr(entry.length) + "</li>");
|
||||
break;
|
||||
} else if (entry.length >= instance.options.partialChars &&
|
||||
} else if (entry.length >= instance.options.partialChars &&
|
||||
instance.options.partialSearch && foundPos != -1) {
|
||||
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
|
||||
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
|
||||
|
@ -450,14 +450,14 @@ Autocompleter.Local = Class.create(Autocompleter.Base, {
|
|||
}
|
||||
}
|
||||
|
||||
foundPos = instance.options.ignoreCase ?
|
||||
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
|
||||
foundPos = instance.options.ignoreCase ?
|
||||
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
|
||||
elem.indexOf(entry, foundPos + 1);
|
||||
|
||||
}
|
||||
}
|
||||
if (partial.length)
|
||||
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
||||
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
|
||||
return "<ul>" + ret.join('') + "</ul>";
|
||||
}
|
||||
}, options || { });
|
||||
|
@ -474,7 +474,7 @@ Field.scrollFreeActivate = function(field) {
|
|||
setTimeout(function() {
|
||||
Field.activate(field);
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
|
||||
Ajax.InPlaceEditor = Class.create({
|
||||
initialize: function(element, url, options) {
|
||||
|
@ -604,7 +604,7 @@ Ajax.InPlaceEditor = Class.create({
|
|||
this.triggerCallback('onEnterHover');
|
||||
},
|
||||
getText: function() {
|
||||
return this.element.innerHTML;
|
||||
return this.element.innerHTML.unescapeHTML();
|
||||
},
|
||||
handleAJAXFailure: function(transport) {
|
||||
this.triggerCallback('onFailure', transport);
|
||||
|
@ -780,7 +780,7 @@ Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
|
|||
onSuccess: function(transport) {
|
||||
var js = transport.responseText.strip();
|
||||
if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
|
||||
throw 'Server returned an invalid collection representation.';
|
||||
throw('Server returned an invalid collection representation.');
|
||||
this._collection = eval(js);
|
||||
this.checkForExternalText();
|
||||
}.bind(this),
|
||||
|
@ -937,7 +937,7 @@ Ajax.InPlaceCollectionEditor.DefaultOptions = {
|
|||
loadingCollectionText: 'Loading options...'
|
||||
};
|
||||
|
||||
// Delayed observer, like Form.Element.Observer,
|
||||
// Delayed observer, like Form.Element.Observer,
|
||||
// but waits for delay after last key input
|
||||
// Ideal for live-search fields
|
||||
|
||||
|
@ -947,7 +947,7 @@ Form.Element.DelayedObserver = Class.create({
|
|||
this.element = $(element);
|
||||
this.callback = callback;
|
||||
this.timer = null;
|
||||
this.lastValue = $F(this.element);
|
||||
this.lastValue = $F(this.element);
|
||||
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
|
||||
},
|
||||
delayedListener: function(event) {
|
||||
|
@ -960,4 +960,4 @@ Form.Element.DelayedObserver = Class.create({
|
|||
this.timer = null;
|
||||
this.callback(this.element, $F(this.element));
|
||||
}
|
||||
});
|
||||
});
|
331
public/javascripts/dragdrop.js
vendored
331
public/javascripts/dragdrop.js
vendored
|
@ -1,6 +1,6 @@
|
|||
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
|
||||
//
|
||||
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
|
||||
//
|
||||
// script.aculo.us is freely distributable under the terms of an MIT-style license.
|
||||
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
||||
|
||||
|
@ -32,7 +32,7 @@ var Droppables = {
|
|||
options._containers.push($(containment));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(options.accept) options.accept = [options.accept].flatten();
|
||||
|
||||
Element.makePositioned(element); // fix IE
|
||||
|
@ -40,34 +40,34 @@ var Droppables = {
|
|||
|
||||
this.drops.push(options);
|
||||
},
|
||||
|
||||
|
||||
findDeepestChild: function(drops) {
|
||||
deepest = drops[0];
|
||||
|
||||
|
||||
for (i = 1; i < drops.length; ++i)
|
||||
if (Element.isParent(drops[i].element, deepest.element))
|
||||
deepest = drops[i];
|
||||
|
||||
|
||||
return deepest;
|
||||
},
|
||||
|
||||
isContained: function(element, drop) {
|
||||
var containmentNode;
|
||||
if(drop.tree) {
|
||||
containmentNode = element.treeNode;
|
||||
containmentNode = element.treeNode;
|
||||
} else {
|
||||
containmentNode = element.parentNode;
|
||||
}
|
||||
return drop._containers.detect(function(c) { return containmentNode == c });
|
||||
},
|
||||
|
||||
|
||||
isAffected: function(point, element, drop) {
|
||||
return (
|
||||
(drop.element!=element) &&
|
||||
((!drop._containers) ||
|
||||
this.isContained(element, drop)) &&
|
||||
((!drop.accept) ||
|
||||
(Element.classNames(element).detect(
|
||||
(Element.classNames(element).detect(
|
||||
function(v) { return drop.accept.include(v) } ) )) &&
|
||||
Position.within(drop.element, point[0], point[1]) );
|
||||
},
|
||||
|
@ -87,12 +87,12 @@ var Droppables = {
|
|||
show: function(point, element) {
|
||||
if(!this.drops.length) return;
|
||||
var drop, affected = [];
|
||||
|
||||
|
||||
this.drops.each( function(drop) {
|
||||
if(Droppables.isAffected(point, element, drop))
|
||||
affected.push(drop);
|
||||
});
|
||||
|
||||
|
||||
if(affected.length>0)
|
||||
drop = Droppables.findDeepestChild(affected);
|
||||
|
||||
|
@ -101,7 +101,7 @@ var Droppables = {
|
|||
Position.within(drop.element, point[0], point[1]);
|
||||
if(drop.onHover)
|
||||
drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
|
||||
|
||||
|
||||
if (drop != this.last_active) Droppables.activate(drop);
|
||||
}
|
||||
},
|
||||
|
@ -112,8 +112,8 @@ var Droppables = {
|
|||
|
||||
if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
|
||||
if (this.last_active.onDrop) {
|
||||
this.last_active.onDrop(element, this.last_active.element, event);
|
||||
return true;
|
||||
this.last_active.onDrop(element, this.last_active.element, event);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -121,25 +121,25 @@ var Droppables = {
|
|||
if(this.last_active)
|
||||
this.deactivate(this.last_active);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var Draggables = {
|
||||
drags: [],
|
||||
observers: [],
|
||||
|
||||
|
||||
register: function(draggable) {
|
||||
if(this.drags.length == 0) {
|
||||
this.eventMouseUp = this.endDrag.bindAsEventListener(this);
|
||||
this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
|
||||
this.eventKeypress = this.keyPress.bindAsEventListener(this);
|
||||
|
||||
|
||||
Event.observe(document, "mouseup", this.eventMouseUp);
|
||||
Event.observe(document, "mousemove", this.eventMouseMove);
|
||||
Event.observe(document, "keypress", this.eventKeypress);
|
||||
}
|
||||
this.drags.push(draggable);
|
||||
},
|
||||
|
||||
|
||||
unregister: function(draggable) {
|
||||
this.drags = this.drags.reject(function(d) { return d==draggable });
|
||||
if(this.drags.length == 0) {
|
||||
|
@ -148,24 +148,24 @@ var Draggables = {
|
|||
Event.stopObserving(document, "keypress", this.eventKeypress);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
activate: function(draggable) {
|
||||
if(draggable.options.delay) {
|
||||
this._timeout = setTimeout(function() {
|
||||
Draggables._timeout = null;
|
||||
window.focus();
|
||||
Draggables.activeDraggable = draggable;
|
||||
}.bind(this), draggable.options.delay);
|
||||
if(draggable.options.delay) {
|
||||
this._timeout = setTimeout(function() {
|
||||
Draggables._timeout = null;
|
||||
window.focus();
|
||||
Draggables.activeDraggable = draggable;
|
||||
}.bind(this), draggable.options.delay);
|
||||
} else {
|
||||
window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
|
||||
this.activeDraggable = draggable;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
deactivate: function() {
|
||||
this.activeDraggable = null;
|
||||
},
|
||||
|
||||
|
||||
updateDrag: function(event) {
|
||||
if(!this.activeDraggable) return;
|
||||
var pointer = [Event.pointerX(event), Event.pointerY(event)];
|
||||
|
@ -173,36 +173,36 @@ var Draggables = {
|
|||
// the same coordinates, prevent needless redrawing (moz bug?)
|
||||
if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
|
||||
this._lastPointer = pointer;
|
||||
|
||||
|
||||
this.activeDraggable.updateDrag(event, pointer);
|
||||
},
|
||||
|
||||
|
||||
endDrag: function(event) {
|
||||
if(this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = null;
|
||||
if(this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = null;
|
||||
}
|
||||
if(!this.activeDraggable) return;
|
||||
this._lastPointer = null;
|
||||
this.activeDraggable.endDrag(event);
|
||||
this.activeDraggable = null;
|
||||
},
|
||||
|
||||
|
||||
keyPress: function(event) {
|
||||
if(this.activeDraggable)
|
||||
this.activeDraggable.keyPress(event);
|
||||
},
|
||||
|
||||
|
||||
addObserver: function(observer) {
|
||||
this.observers.push(observer);
|
||||
this._cacheObserverCallbacks();
|
||||
},
|
||||
|
||||
|
||||
removeObserver: function(element) { // element instead of observer fixes mem leaks
|
||||
this.observers = this.observers.reject( function(o) { return o.element==element });
|
||||
this._cacheObserverCallbacks();
|
||||
},
|
||||
|
||||
|
||||
notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
|
||||
if(this[eventName+'Count'] > 0)
|
||||
this.observers.each( function(o) {
|
||||
|
@ -210,7 +210,7 @@ var Draggables = {
|
|||
});
|
||||
if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
|
||||
},
|
||||
|
||||
|
||||
_cacheObserverCallbacks: function() {
|
||||
['onStart','onEnd','onDrag'].each( function(eventName) {
|
||||
Draggables[eventName+'Count'] = Draggables.observers.select(
|
||||
|
@ -218,7 +218,7 @@ var Draggables = {
|
|||
).length;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -234,12 +234,12 @@ var Draggable = Class.create({
|
|||
},
|
||||
endeffect: function(element) {
|
||||
var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
|
||||
new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
|
||||
new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
|
||||
queue: {scope:'_draggable', position:'end'},
|
||||
afterFinish: function(){
|
||||
Draggable._dragging[element] = false
|
||||
afterFinish: function(){
|
||||
Draggable._dragging[element] = false
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
zindex: 1000,
|
||||
revert: false,
|
||||
|
@ -250,57 +250,57 @@ var Draggable = Class.create({
|
|||
snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
|
||||
delay: 0
|
||||
};
|
||||
|
||||
|
||||
if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
|
||||
Object.extend(defaults, {
|
||||
starteffect: function(element) {
|
||||
element._opacity = Element.getOpacity(element);
|
||||
Draggable._dragging[element] = true;
|
||||
new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
|
||||
new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var options = Object.extend(defaults, arguments[1] || { });
|
||||
|
||||
this.element = $(element);
|
||||
|
||||
|
||||
if(options.handle && Object.isString(options.handle))
|
||||
this.handle = this.element.down('.'+options.handle, 0);
|
||||
|
||||
|
||||
if(!this.handle) this.handle = $(options.handle);
|
||||
if(!this.handle) this.handle = this.element;
|
||||
|
||||
|
||||
if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
|
||||
options.scroll = $(options.scroll);
|
||||
this._isScrollChild = Element.childOf(this.element, options.scroll);
|
||||
}
|
||||
|
||||
Element.makePositioned(this.element); // fix IE
|
||||
Element.makePositioned(this.element); // fix IE
|
||||
|
||||
this.options = options;
|
||||
this.dragging = false;
|
||||
this.dragging = false;
|
||||
|
||||
this.eventMouseDown = this.initDrag.bindAsEventListener(this);
|
||||
Event.observe(this.handle, "mousedown", this.eventMouseDown);
|
||||
|
||||
|
||||
Draggables.register(this);
|
||||
},
|
||||
|
||||
|
||||
destroy: function() {
|
||||
Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
|
||||
Draggables.unregister(this);
|
||||
},
|
||||
|
||||
|
||||
currentDelta: function() {
|
||||
return([
|
||||
parseInt(Element.getStyle(this.element,'left') || '0'),
|
||||
parseInt(Element.getStyle(this.element,'top') || '0')]);
|
||||
},
|
||||
|
||||
|
||||
initDrag: function(event) {
|
||||
if(!Object.isUndefined(Draggable._dragging[this.element]) &&
|
||||
Draggable._dragging[this.element]) return;
|
||||
if(Event.isLeftClick(event)) {
|
||||
if(Event.isLeftClick(event)) {
|
||||
// abort on form elements, fixes a Firefox issue
|
||||
var src = Event.element(event);
|
||||
if((tag_name = src.tagName.toUpperCase()) && (
|
||||
|
@ -309,34 +309,34 @@ var Draggable = Class.create({
|
|||
tag_name=='OPTION' ||
|
||||
tag_name=='BUTTON' ||
|
||||
tag_name=='TEXTAREA')) return;
|
||||
|
||||
|
||||
var pointer = [Event.pointerX(event), Event.pointerY(event)];
|
||||
var pos = Position.cumulativeOffset(this.element);
|
||||
this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
|
||||
|
||||
|
||||
Draggables.activate(this);
|
||||
Event.stop(event);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
startDrag: function(event) {
|
||||
this.dragging = true;
|
||||
if(!this.delta)
|
||||
this.delta = this.currentDelta();
|
||||
|
||||
|
||||
if(this.options.zindex) {
|
||||
this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
|
||||
this.element.style.zIndex = this.options.zindex;
|
||||
}
|
||||
|
||||
|
||||
if(this.options.ghosting) {
|
||||
this._clone = this.element.cloneNode(true);
|
||||
this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
|
||||
if (!this.element._originallyAbsolute)
|
||||
this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
|
||||
if (!this._originallyAbsolute)
|
||||
Position.absolutize(this.element);
|
||||
this.element.parentNode.insertBefore(this._clone, this.element);
|
||||
}
|
||||
|
||||
|
||||
if(this.options.scroll) {
|
||||
if (this.options.scroll == window) {
|
||||
var where = this._getWindowScroll(this.options.scroll);
|
||||
|
@ -347,28 +347,28 @@ var Draggable = Class.create({
|
|||
this.originalScrollTop = this.options.scroll.scrollTop;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Draggables.notify('onStart', this, event);
|
||||
|
||||
|
||||
if(this.options.starteffect) this.options.starteffect(this.element);
|
||||
},
|
||||
|
||||
|
||||
updateDrag: function(event, pointer) {
|
||||
if(!this.dragging) this.startDrag(event);
|
||||
|
||||
|
||||
if(!this.options.quiet){
|
||||
Position.prepare();
|
||||
Droppables.show(pointer, this.element);
|
||||
}
|
||||
|
||||
|
||||
Draggables.notify('onDrag', this, event);
|
||||
|
||||
|
||||
this.draw(pointer);
|
||||
if(this.options.change) this.options.change(this);
|
||||
|
||||
|
||||
if(this.options.scroll) {
|
||||
this.stopScrolling();
|
||||
|
||||
|
||||
var p;
|
||||
if (this.options.scroll == window) {
|
||||
with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
|
||||
|
@ -386,16 +386,16 @@ var Draggable = Class.create({
|
|||
if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
|
||||
this.startScrolling(speed);
|
||||
}
|
||||
|
||||
|
||||
// fix AppleWebKit rendering
|
||||
if(Prototype.Browser.WebKit) window.scrollBy(0,0);
|
||||
|
||||
|
||||
Event.stop(event);
|
||||
},
|
||||
|
||||
|
||||
finishDrag: function(event, success) {
|
||||
this.dragging = false;
|
||||
|
||||
|
||||
if(this.options.quiet){
|
||||
Position.prepare();
|
||||
var pointer = [Event.pointerX(event), Event.pointerY(event)];
|
||||
|
@ -403,24 +403,24 @@ var Draggable = Class.create({
|
|||
}
|
||||
|
||||
if(this.options.ghosting) {
|
||||
if (!this.element._originallyAbsolute)
|
||||
if (!this._originallyAbsolute)
|
||||
Position.relativize(this.element);
|
||||
delete this.element._originallyAbsolute;
|
||||
delete this._originallyAbsolute;
|
||||
Element.remove(this._clone);
|
||||
this._clone = null;
|
||||
}
|
||||
|
||||
var dropped = false;
|
||||
if(success) {
|
||||
dropped = Droppables.fire(event, this.element);
|
||||
if (!dropped) dropped = false;
|
||||
var dropped = false;
|
||||
if(success) {
|
||||
dropped = Droppables.fire(event, this.element);
|
||||
if (!dropped) dropped = false;
|
||||
}
|
||||
if(dropped && this.options.onDropped) this.options.onDropped(this.element);
|
||||
Draggables.notify('onEnd', this, event);
|
||||
|
||||
var revert = this.options.revert;
|
||||
if(revert && Object.isFunction(revert)) revert = revert(this.element);
|
||||
|
||||
|
||||
var d = this.currentDelta();
|
||||
if(revert && this.options.reverteffect) {
|
||||
if (dropped == 0 || revert != 'failure')
|
||||
|
@ -433,67 +433,67 @@ var Draggable = Class.create({
|
|||
if(this.options.zindex)
|
||||
this.element.style.zIndex = this.originalZ;
|
||||
|
||||
if(this.options.endeffect)
|
||||
if(this.options.endeffect)
|
||||
this.options.endeffect(this.element);
|
||||
|
||||
|
||||
Draggables.deactivate(this);
|
||||
Droppables.reset();
|
||||
},
|
||||
|
||||
|
||||
keyPress: function(event) {
|
||||
if(event.keyCode!=Event.KEY_ESC) return;
|
||||
this.finishDrag(event, false);
|
||||
Event.stop(event);
|
||||
},
|
||||
|
||||
|
||||
endDrag: function(event) {
|
||||
if(!this.dragging) return;
|
||||
this.stopScrolling();
|
||||
this.finishDrag(event, true);
|
||||
Event.stop(event);
|
||||
},
|
||||
|
||||
|
||||
draw: function(point) {
|
||||
var pos = Position.cumulativeOffset(this.element);
|
||||
if(this.options.ghosting) {
|
||||
var r = Position.realOffset(this.element);
|
||||
pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
|
||||
}
|
||||
|
||||
|
||||
var d = this.currentDelta();
|
||||
pos[0] -= d[0]; pos[1] -= d[1];
|
||||
|
||||
|
||||
if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
|
||||
pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
|
||||
pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
|
||||
}
|
||||
|
||||
var p = [0,1].map(function(i){
|
||||
return (point[i]-pos[i]-this.offset[i])
|
||||
|
||||
var p = [0,1].map(function(i){
|
||||
return (point[i]-pos[i]-this.offset[i])
|
||||
}.bind(this));
|
||||
|
||||
|
||||
if(this.options.snap) {
|
||||
if(Object.isFunction(this.options.snap)) {
|
||||
p = this.options.snap(p[0],p[1],this);
|
||||
} else {
|
||||
if(Object.isArray(this.options.snap)) {
|
||||
p = p.map( function(v, i) {
|
||||
return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
|
||||
return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
|
||||
} else {
|
||||
p = p.map( function(v) {
|
||||
return (v/this.options.snap).round()*this.options.snap }.bind(this))
|
||||
return (v/this.options.snap).round()*this.options.snap }.bind(this));
|
||||
}
|
||||
}}
|
||||
|
||||
|
||||
var style = this.element.style;
|
||||
if((!this.options.constraint) || (this.options.constraint=='horizontal'))
|
||||
style.left = p[0] + "px";
|
||||
if((!this.options.constraint) || (this.options.constraint=='vertical'))
|
||||
style.top = p[1] + "px";
|
||||
|
||||
|
||||
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
|
||||
},
|
||||
|
||||
|
||||
stopScrolling: function() {
|
||||
if(this.scrollInterval) {
|
||||
clearInterval(this.scrollInterval);
|
||||
|
@ -501,14 +501,14 @@ var Draggable = Class.create({
|
|||
Draggables._lastScrollPointer = null;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
startScrolling: function(speed) {
|
||||
if(!(speed[0] || speed[1])) return;
|
||||
this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
|
||||
this.lastScrolled = new Date();
|
||||
this.scrollInterval = setInterval(this.scroll.bind(this), 10);
|
||||
},
|
||||
|
||||
|
||||
scroll: function() {
|
||||
var current = new Date();
|
||||
var delta = current - this.lastScrolled;
|
||||
|
@ -524,7 +524,7 @@ var Draggable = Class.create({
|
|||
this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
|
||||
this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
|
||||
}
|
||||
|
||||
|
||||
Position.prepare();
|
||||
Droppables.show(Draggables._lastPointer, this.element);
|
||||
Draggables.notify('onDrag', this);
|
||||
|
@ -538,10 +538,10 @@ var Draggable = Class.create({
|
|||
Draggables._lastScrollPointer[1] = 0;
|
||||
this.draw(Draggables._lastScrollPointer);
|
||||
}
|
||||
|
||||
|
||||
if(this.options.change) this.options.change(this);
|
||||
},
|
||||
|
||||
|
||||
_getWindowScroll: function(w) {
|
||||
var T, L, W, H;
|
||||
with (w.document) {
|
||||
|
@ -560,7 +560,7 @@ var Draggable = Class.create({
|
|||
H = documentElement.clientHeight;
|
||||
} else {
|
||||
W = body.offsetWidth;
|
||||
H = body.offsetHeight
|
||||
H = body.offsetHeight;
|
||||
}
|
||||
}
|
||||
return { top: T, left: L, width: W, height: H };
|
||||
|
@ -577,11 +577,11 @@ var SortableObserver = Class.create({
|
|||
this.observer = observer;
|
||||
this.lastValue = Sortable.serialize(this.element);
|
||||
},
|
||||
|
||||
|
||||
onStart: function() {
|
||||
this.lastValue = Sortable.serialize(this.element);
|
||||
},
|
||||
|
||||
|
||||
onEnd: function() {
|
||||
Sortable.unmark();
|
||||
if(this.lastValue != Sortable.serialize(this.element))
|
||||
|
@ -591,11 +591,11 @@ var SortableObserver = Class.create({
|
|||
|
||||
var Sortable = {
|
||||
SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
|
||||
|
||||
|
||||
sortables: { },
|
||||
|
||||
|
||||
_findRootElement: function(element) {
|
||||
while (element.tagName.toUpperCase() != "BODY") {
|
||||
while (element.tagName.toUpperCase() != "BODY") {
|
||||
if(element.id && Sortable.sortables[element.id]) return element;
|
||||
element = element.parentNode;
|
||||
}
|
||||
|
@ -606,22 +606,23 @@ var Sortable = {
|
|||
if(!element) return;
|
||||
return Sortable.sortables[element.id];
|
||||
},
|
||||
|
||||
|
||||
destroy: function(element){
|
||||
var s = Sortable.options(element);
|
||||
|
||||
element = $(element);
|
||||
var s = Sortable.sortables[element.id];
|
||||
|
||||
if(s) {
|
||||
Draggables.removeObserver(s.element);
|
||||
s.droppables.each(function(d){ Droppables.remove(d) });
|
||||
s.draggables.invoke('destroy');
|
||||
|
||||
|
||||
delete Sortable.sortables[s.element.id];
|
||||
}
|
||||
},
|
||||
|
||||
create: function(element) {
|
||||
element = $(element);
|
||||
var options = Object.extend({
|
||||
var options = Object.extend({
|
||||
element: element,
|
||||
tag: 'li', // assumes li children, override with tag: 'tagname'
|
||||
dropOnEmpty: false,
|
||||
|
@ -635,17 +636,17 @@ var Sortable = {
|
|||
delay: 0,
|
||||
hoverclass: null,
|
||||
ghosting: false,
|
||||
quiet: false,
|
||||
quiet: false,
|
||||
scroll: false,
|
||||
scrollSensitivity: 20,
|
||||
scrollSpeed: 15,
|
||||
format: this.SERIALIZE_RULE,
|
||||
|
||||
// these take arrays of elements or ids and can be
|
||||
|
||||
// these take arrays of elements or ids and can be
|
||||
// used for better initialization performance
|
||||
elements: false,
|
||||
handles: false,
|
||||
|
||||
|
||||
onChange: Prototype.emptyFunction,
|
||||
onUpdate: Prototype.emptyFunction
|
||||
}, arguments[1] || { });
|
||||
|
@ -682,24 +683,24 @@ var Sortable = {
|
|||
if(options.zindex)
|
||||
options_for_draggable.zindex = options.zindex;
|
||||
|
||||
// build options for the droppables
|
||||
// build options for the droppables
|
||||
var options_for_droppable = {
|
||||
overlap: options.overlap,
|
||||
containment: options.containment,
|
||||
tree: options.tree,
|
||||
hoverclass: options.hoverclass,
|
||||
onHover: Sortable.onHover
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var options_for_tree = {
|
||||
onHover: Sortable.onEmptyHover,
|
||||
overlap: options.overlap,
|
||||
containment: options.containment,
|
||||
hoverclass: options.hoverclass
|
||||
}
|
||||
};
|
||||
|
||||
// fix for gecko engine
|
||||
Element.cleanWhitespace(element);
|
||||
Element.cleanWhitespace(element);
|
||||
|
||||
options.draggables = [];
|
||||
options.droppables = [];
|
||||
|
@ -712,14 +713,14 @@ var Sortable = {
|
|||
|
||||
(options.elements || this.findElements(element, options) || []).each( function(e,i) {
|
||||
var handle = options.handles ? $(options.handles[i]) :
|
||||
(options.handle ? $(e).select('.' + options.handle)[0] : e);
|
||||
(options.handle ? $(e).select('.' + options.handle)[0] : e);
|
||||
options.draggables.push(
|
||||
new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
|
||||
Droppables.add(e, options_for_droppable);
|
||||
if(options.tree) e.treeNode = element;
|
||||
options.droppables.push(e);
|
||||
options.droppables.push(e);
|
||||
});
|
||||
|
||||
|
||||
if(options.tree) {
|
||||
(Sortable.findTreeElements(element, options) || []).each( function(e) {
|
||||
Droppables.add(e, options_for_tree);
|
||||
|
@ -741,7 +742,7 @@ var Sortable = {
|
|||
return Element.findChildren(
|
||||
element, options.only, options.tree ? true : false, options.tag);
|
||||
},
|
||||
|
||||
|
||||
findTreeElements: function(element, options) {
|
||||
return Element.findChildren(
|
||||
element, options.only, options.tree ? true : false, options.treeTag);
|
||||
|
@ -758,7 +759,7 @@ var Sortable = {
|
|||
var oldParentNode = element.parentNode;
|
||||
element.style.visibility = "hidden"; // fix gecko rendering
|
||||
dropon.parentNode.insertBefore(element, dropon);
|
||||
if(dropon.parentNode!=oldParentNode)
|
||||
if(dropon.parentNode!=oldParentNode)
|
||||
Sortable.options(oldParentNode).onChange(element);
|
||||
Sortable.options(dropon.parentNode).onChange(element);
|
||||
}
|
||||
|
@ -769,26 +770,26 @@ var Sortable = {
|
|||
var oldParentNode = element.parentNode;
|
||||
element.style.visibility = "hidden"; // fix gecko rendering
|
||||
dropon.parentNode.insertBefore(element, nextElement);
|
||||
if(dropon.parentNode!=oldParentNode)
|
||||
if(dropon.parentNode!=oldParentNode)
|
||||
Sortable.options(oldParentNode).onChange(element);
|
||||
Sortable.options(dropon.parentNode).onChange(element);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
onEmptyHover: function(element, dropon, overlap) {
|
||||
var oldParentNode = element.parentNode;
|
||||
var droponOptions = Sortable.options(dropon);
|
||||
|
||||
|
||||
if(!Element.isParent(dropon, element)) {
|
||||
var index;
|
||||
|
||||
|
||||
var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
|
||||
var child = null;
|
||||
|
||||
|
||||
if(children) {
|
||||
var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
|
||||
|
||||
|
||||
for (index = 0; index < children.length; index += 1) {
|
||||
if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
|
||||
offset -= Element.offsetSize (children[index], droponOptions.overlap);
|
||||
|
@ -801,9 +802,9 @@ var Sortable = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dropon.insertBefore(element, child);
|
||||
|
||||
|
||||
Sortable.options(oldParentNode).onChange(element);
|
||||
droponOptions.onChange(element);
|
||||
}
|
||||
|
@ -816,34 +817,34 @@ var Sortable = {
|
|||
mark: function(dropon, position) {
|
||||
// mark on ghosting only
|
||||
var sortable = Sortable.options(dropon.parentNode);
|
||||
if(sortable && !sortable.ghosting) return;
|
||||
if(sortable && !sortable.ghosting) return;
|
||||
|
||||
if(!Sortable._marker) {
|
||||
Sortable._marker =
|
||||
Sortable._marker =
|
||||
($('dropmarker') || Element.extend(document.createElement('DIV'))).
|
||||
hide().addClassName('dropmarker').setStyle({position:'absolute'});
|
||||
document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
|
||||
}
|
||||
}
|
||||
var offsets = Position.cumulativeOffset(dropon);
|
||||
Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
|
||||
|
||||
|
||||
if(position=='after')
|
||||
if(sortable.overlap == 'horizontal')
|
||||
if(sortable.overlap == 'horizontal')
|
||||
Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
|
||||
else
|
||||
Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
|
||||
|
||||
|
||||
Sortable._marker.show();
|
||||
},
|
||||
|
||||
|
||||
_tree: function(element, options, parent) {
|
||||
var children = Sortable.findElements(element, options) || [];
|
||||
|
||||
|
||||
for (var i = 0; i < children.length; ++i) {
|
||||
var match = children[i].id.match(options.format);
|
||||
|
||||
if (!match) continue;
|
||||
|
||||
|
||||
var child = {
|
||||
id: encodeURIComponent(match ? match[1] : null),
|
||||
element: element,
|
||||
|
@ -851,16 +852,16 @@ var Sortable = {
|
|||
children: [],
|
||||
position: parent.children.length,
|
||||
container: $(children[i]).down(options.treeTag)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* Get the element containing the children and recurse over it */
|
||||
if (child.container)
|
||||
this._tree(child.container, options, child)
|
||||
|
||||
this._tree(child.container, options, child);
|
||||
|
||||
parent.children.push (child);
|
||||
}
|
||||
|
||||
return parent;
|
||||
return parent;
|
||||
},
|
||||
|
||||
tree: function(element) {
|
||||
|
@ -873,15 +874,15 @@ var Sortable = {
|
|||
name: element.id,
|
||||
format: sortableOptions.format
|
||||
}, arguments[1] || { });
|
||||
|
||||
|
||||
var root = {
|
||||
id: null,
|
||||
parent: null,
|
||||
children: [],
|
||||
container: element,
|
||||
position: 0
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return Sortable._tree(element, options, root);
|
||||
},
|
||||
|
||||
|
@ -897,7 +898,7 @@ var Sortable = {
|
|||
sequence: function(element) {
|
||||
element = $(element);
|
||||
var options = Object.extend(this.options(element), arguments[1] || { });
|
||||
|
||||
|
||||
return $(this.findElements(element, options) || []).map( function(item) {
|
||||
return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
|
||||
});
|
||||
|
@ -906,14 +907,14 @@ var Sortable = {
|
|||
setSequence: function(element, new_sequence) {
|
||||
element = $(element);
|
||||
var options = Object.extend(this.options(element), arguments[2] || { });
|
||||
|
||||
|
||||
var nodeMap = { };
|
||||
this.findElements(element, options).each( function(n) {
|
||||
if (n.id.match(options.format))
|
||||
nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
|
||||
n.parentNode.removeChild(n);
|
||||
});
|
||||
|
||||
|
||||
new_sequence.each(function(ident) {
|
||||
var n = nodeMap[ident];
|
||||
if (n) {
|
||||
|
@ -922,16 +923,16 @@ var Sortable = {
|
|||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
serialize: function(element) {
|
||||
element = $(element);
|
||||
var options = Object.extend(Sortable.options(element), arguments[1] || { });
|
||||
var name = encodeURIComponent(
|
||||
(arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
|
||||
|
||||
|
||||
if (options.tree) {
|
||||
return Sortable.tree(element, arguments[1]).children.map( function (item) {
|
||||
return [name + Sortable._constructIndex(item) + "[id]=" +
|
||||
return [name + Sortable._constructIndex(item) + "[id]=" +
|
||||
encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
|
||||
}).flatten().join('&');
|
||||
} else {
|
||||
|
@ -940,16 +941,16 @@ var Sortable = {
|
|||
}).join('&');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Returns true if child is contained within element
|
||||
Element.isParent = function(child, element) {
|
||||
if (!child.parentNode || child == element) return false;
|
||||
if (child.parentNode == element) return true;
|
||||
return Element.isParent(child.parentNode, element);
|
||||
}
|
||||
};
|
||||
|
||||
Element.findChildren = function(element, only, recursive, tagName) {
|
||||
Element.findChildren = function(element, only, recursive, tagName) {
|
||||
if(!element.hasChildNodes()) return null;
|
||||
tagName = tagName.toUpperCase();
|
||||
if(only) only = [only].flatten();
|
||||
|
@ -965,8 +966,8 @@ Element.findChildren = function(element, only, recursive, tagName) {
|
|||
});
|
||||
|
||||
return (elements.length>0 ? elements.flatten() : []);
|
||||
}
|
||||
};
|
||||
|
||||
Element.offsetSize = function (element, type) {
|
||||
return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
|
||||
}
|
||||
};
|
340
public/javascripts/effects.js
vendored
340
public/javascripts/effects.js
vendored
|
@ -1,48 +1,48 @@
|
|||
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// Contributors:
|
||||
// Justin Palmer (http://encytemedia.com/)
|
||||
// Mark Pilgrim (http://diveintomark.org/)
|
||||
// Martin Bialasinki
|
||||
//
|
||||
//
|
||||
// script.aculo.us is freely distributable under the terms of an MIT-style license.
|
||||
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
||||
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
||||
|
||||
// converts rgb() and #xxx to #xxxxxx format,
|
||||
// returns self (or first argument) if not convertable
|
||||
String.prototype.parseColor = function() {
|
||||
// converts rgb() and #xxx to #xxxxxx format,
|
||||
// returns self (or first argument) if not convertable
|
||||
String.prototype.parseColor = function() {
|
||||
var color = '#';
|
||||
if (this.slice(0,4) == 'rgb(') {
|
||||
var cols = this.slice(4,this.length-1).split(',');
|
||||
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
|
||||
} else {
|
||||
if (this.slice(0,1) == '#') {
|
||||
if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
|
||||
if (this.length==7) color = this.toLowerCase();
|
||||
}
|
||||
}
|
||||
return (color.length==7 ? color : (arguments[0] || this));
|
||||
if (this.slice(0,4) == 'rgb(') {
|
||||
var cols = this.slice(4,this.length-1).split(',');
|
||||
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
|
||||
} else {
|
||||
if (this.slice(0,1) == '#') {
|
||||
if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
|
||||
if (this.length==7) color = this.toLowerCase();
|
||||
}
|
||||
}
|
||||
return (color.length==7 ? color : (arguments[0] || this));
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
Element.collectTextNodes = function(element) {
|
||||
Element.collectTextNodes = function(element) {
|
||||
return $A($(element).childNodes).collect( function(node) {
|
||||
return (node.nodeType==3 ? node.nodeValue :
|
||||
return (node.nodeType==3 ? node.nodeValue :
|
||||
(node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
|
||||
}).flatten().join('');
|
||||
};
|
||||
|
||||
Element.collectTextNodesIgnoreClass = function(element, className) {
|
||||
Element.collectTextNodesIgnoreClass = function(element, className) {
|
||||
return $A($(element).childNodes).collect( function(node) {
|
||||
return (node.nodeType==3 ? node.nodeValue :
|
||||
((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
|
||||
return (node.nodeType==3 ? node.nodeValue :
|
||||
((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
|
||||
Element.collectTextNodesIgnoreClass(node, className) : ''));
|
||||
}).flatten().join('');
|
||||
};
|
||||
|
||||
Element.setContentZoom = function(element, percent) {
|
||||
element = $(element);
|
||||
element.setStyle({fontSize: (percent/100) + 'em'});
|
||||
element = $(element);
|
||||
element.setStyle({fontSize: (percent/100) + 'em'});
|
||||
if (Prototype.Browser.WebKit) window.scrollBy(0,0);
|
||||
return element;
|
||||
};
|
||||
|
@ -70,28 +70,23 @@ var Effect = {
|
|||
Transitions: {
|
||||
linear: Prototype.K,
|
||||
sinoidal: function(pos) {
|
||||
return (-Math.cos(pos*Math.PI)/2) + 0.5;
|
||||
return (-Math.cos(pos*Math.PI)/2) + .5;
|
||||
},
|
||||
reverse: function(pos) {
|
||||
return 1-pos;
|
||||
},
|
||||
flicker: function(pos) {
|
||||
var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
|
||||
var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
|
||||
return pos > 1 ? 1 : pos;
|
||||
},
|
||||
wobble: function(pos) {
|
||||
return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
|
||||
return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
|
||||
},
|
||||
pulse: function(pos, pulses) {
|
||||
pulses = pulses || 5;
|
||||
return (
|
||||
((pos % (1/pulses)) * pulses).round() == 0 ?
|
||||
((pos * pulses * 2) - (pos * pulses * 2).floor()) :
|
||||
1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
|
||||
);
|
||||
pulse: function(pos, pulses) {
|
||||
return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
|
||||
},
|
||||
spring: function(pos) {
|
||||
return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
|
||||
spring: function(pos) {
|
||||
return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
|
||||
},
|
||||
none: function(pos) {
|
||||
return 0;
|
||||
|
@ -112,14 +107,14 @@ var Effect = {
|
|||
tagifyText: function(element) {
|
||||
var tagifyStyle = 'position:relative';
|
||||
if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
|
||||
|
||||
|
||||
element = $(element);
|
||||
$A(element.childNodes).each( function(child) {
|
||||
if (child.nodeType==3) {
|
||||
child.nodeValue.toArray().each( function(character) {
|
||||
element.insertBefore(
|
||||
new Element('span', {style: tagifyStyle}).update(
|
||||
character == ' ' ? String.fromCharCode(160) : character),
|
||||
character == ' ' ? String.fromCharCode(160) : character),
|
||||
child);
|
||||
});
|
||||
Element.remove(child);
|
||||
|
@ -128,13 +123,13 @@ var Effect = {
|
|||
},
|
||||
multiple: function(element, effect) {
|
||||
var elements;
|
||||
if (((typeof element == 'object') ||
|
||||
Object.isFunction(element)) &&
|
||||
if (((typeof element == 'object') ||
|
||||
Object.isFunction(element)) &&
|
||||
(element.length))
|
||||
elements = element;
|
||||
else
|
||||
elements = $(element).childNodes;
|
||||
|
||||
|
||||
var options = Object.extend({
|
||||
speed: 0.1,
|
||||
delay: 0.0
|
||||
|
@ -156,7 +151,7 @@ var Effect = {
|
|||
var options = Object.extend({
|
||||
queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
|
||||
}, arguments[2] || { });
|
||||
Effect[element.visible() ?
|
||||
Effect[element.visible() ?
|
||||
Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
|
||||
}
|
||||
};
|
||||
|
@ -168,20 +163,20 @@ Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
|
|||
Effect.ScopedQueue = Class.create(Enumerable, {
|
||||
initialize: function() {
|
||||
this.effects = [];
|
||||
this.interval = null;
|
||||
this.interval = null;
|
||||
},
|
||||
_each: function(iterator) {
|
||||
this.effects._each(iterator);
|
||||
},
|
||||
add: function(effect) {
|
||||
var timestamp = new Date().getTime();
|
||||
|
||||
var position = Object.isString(effect.options.queue) ?
|
||||
|
||||
var position = Object.isString(effect.options.queue) ?
|
||||
effect.options.queue : effect.options.queue.position;
|
||||
|
||||
|
||||
switch(position) {
|
||||
case 'front':
|
||||
// move unstarted effects after this effect
|
||||
// move unstarted effects after this effect
|
||||
this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
|
||||
e.startOn += effect.finishOn;
|
||||
e.finishOn += effect.finishOn;
|
||||
|
@ -195,13 +190,13 @@ Effect.ScopedQueue = Class.create(Enumerable, {
|
|||
timestamp = this.effects.pluck('finishOn').max() || timestamp;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
effect.startOn += timestamp;
|
||||
effect.finishOn += timestamp;
|
||||
|
||||
if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
|
||||
this.effects.push(effect);
|
||||
|
||||
|
||||
if (!this.interval)
|
||||
this.interval = setInterval(this.loop.bind(this), 15);
|
||||
},
|
||||
|
@ -214,7 +209,7 @@ Effect.ScopedQueue = Class.create(Enumerable, {
|
|||
},
|
||||
loop: function() {
|
||||
var timePos = new Date().getTime();
|
||||
for(var i=0, len=this.effects.length;i<len;i++)
|
||||
for(var i=0, len=this.effects.length;i<len;i++)
|
||||
this.effects[i] && this.effects[i].loop(timePos);
|
||||
}
|
||||
});
|
||||
|
@ -223,7 +218,7 @@ Effect.Queues = {
|
|||
instances: $H(),
|
||||
get: function(queueName) {
|
||||
if (!Object.isString(queueName)) return queueName;
|
||||
|
||||
|
||||
return this.instances.get(queueName) ||
|
||||
this.instances.set(queueName, new Effect.ScopedQueue());
|
||||
}
|
||||
|
@ -248,23 +243,35 @@ Effect.Base = Class.create({
|
|||
this.fromToDelta = this.options.to-this.options.from;
|
||||
this.totalTime = this.finishOn-this.startOn;
|
||||
this.totalFrames = this.options.fps*this.options.duration;
|
||||
|
||||
eval('this.render = function(pos){ '+
|
||||
'if (this.state=="idle"){this.state="running";'+
|
||||
codeForEvent(this.options,'beforeSetup')+
|
||||
(this.setup ? 'this.setup();':'')+
|
||||
codeForEvent(this.options,'afterSetup')+
|
||||
'};if (this.state=="running"){'+
|
||||
'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
|
||||
'this.position=pos;'+
|
||||
codeForEvent(this.options,'beforeUpdate')+
|
||||
(this.update ? 'this.update(pos);':'')+
|
||||
codeForEvent(this.options,'afterUpdate')+
|
||||
'}}');
|
||||
|
||||
|
||||
this.render = (function() {
|
||||
function dispatch(effect, eventName) {
|
||||
if (effect.options[eventName + 'Internal'])
|
||||
effect.options[eventName + 'Internal'](effect);
|
||||
if (effect.options[eventName])
|
||||
effect.options[eventName](effect);
|
||||
}
|
||||
|
||||
return function(pos) {
|
||||
if (this.state === "idle") {
|
||||
this.state = "running";
|
||||
dispatch(this, 'beforeSetup');
|
||||
if (this.setup) this.setup();
|
||||
dispatch(this, 'afterSetup');
|
||||
}
|
||||
if (this.state === "running") {
|
||||
pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
|
||||
this.position = pos;
|
||||
dispatch(this, 'beforeUpdate');
|
||||
if (this.update) this.update(pos);
|
||||
dispatch(this, 'afterUpdate');
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
this.event('beforeStart');
|
||||
if (!this.options.sync)
|
||||
Effect.Queues.get(Object.isString(this.options.queue) ?
|
||||
Effect.Queues.get(Object.isString(this.options.queue) ?
|
||||
'global' : this.options.queue.scope).add(this);
|
||||
},
|
||||
loop: function(timePos) {
|
||||
|
@ -273,9 +280,9 @@ Effect.Base = Class.create({
|
|||
this.render(1.0);
|
||||
this.cancel();
|
||||
this.event('beforeFinish');
|
||||
if (this.finish) this.finish();
|
||||
if (this.finish) this.finish();
|
||||
this.event('afterFinish');
|
||||
return;
|
||||
return;
|
||||
}
|
||||
var pos = (timePos - this.startOn) / this.totalTime,
|
||||
frame = (pos * this.totalFrames).round();
|
||||
|
@ -287,7 +294,7 @@ Effect.Base = Class.create({
|
|||
},
|
||||
cancel: function() {
|
||||
if (!this.options.sync)
|
||||
Effect.Queues.get(Object.isString(this.options.queue) ?
|
||||
Effect.Queues.get(Object.isString(this.options.queue) ?
|
||||
'global' : this.options.queue.scope).remove(this);
|
||||
this.state = 'finished';
|
||||
},
|
||||
|
@ -325,10 +332,10 @@ Effect.Parallel = Class.create(Effect.Base, {
|
|||
Effect.Tween = Class.create(Effect.Base, {
|
||||
initialize: function(object, from, to) {
|
||||
object = Object.isString(object) ? $(object) : object;
|
||||
var args = $A(arguments), method = args.last(),
|
||||
var args = $A(arguments), method = args.last(),
|
||||
options = args.length == 5 ? args[3] : null;
|
||||
this.method = Object.isFunction(method) ? method.bind(object) :
|
||||
Object.isFunction(object[method]) ? object[method].bind(object) :
|
||||
Object.isFunction(object[method]) ? object[method].bind(object) :
|
||||
function(value) { object[method] = value };
|
||||
this.start(Object.extend({ from: from, to: to }, options || { }));
|
||||
},
|
||||
|
@ -392,7 +399,7 @@ Effect.Move = Class.create(Effect.Base, {
|
|||
|
||||
// for backwards compatibility
|
||||
Effect.MoveBy = function(element, toTop, toLeft) {
|
||||
return new Effect.Move(element,
|
||||
return new Effect.Move(element,
|
||||
Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
|
||||
};
|
||||
|
||||
|
@ -414,15 +421,15 @@ Effect.Scale = Class.create(Effect.Base, {
|
|||
setup: function() {
|
||||
this.restoreAfterFinish = this.options.restoreAfterFinish || false;
|
||||
this.elementPositioning = this.element.getStyle('position');
|
||||
|
||||
|
||||
this.originalStyle = { };
|
||||
['top','left','width','height','fontSize'].each( function(k) {
|
||||
this.originalStyle[k] = this.element.style[k];
|
||||
}.bind(this));
|
||||
|
||||
|
||||
this.originalTop = this.element.offsetTop;
|
||||
this.originalLeft = this.element.offsetLeft;
|
||||
|
||||
|
||||
var fontSize = this.element.getStyle('font-size') || '100%';
|
||||
['em','px','%','pt'].each( function(fontSizeType) {
|
||||
if (fontSize.indexOf(fontSizeType)>0) {
|
||||
|
@ -430,9 +437,9 @@ Effect.Scale = Class.create(Effect.Base, {
|
|||
this.fontSizeType = fontSizeType;
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
|
||||
this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
|
||||
|
||||
|
||||
this.dims = null;
|
||||
if (this.options.scaleMode=='box')
|
||||
this.dims = [this.element.offsetHeight, this.element.offsetWidth];
|
||||
|
@ -507,17 +514,16 @@ Effect.Highlight = Class.create(Effect.Base, {
|
|||
|
||||
Effect.ScrollTo = function(element) {
|
||||
var options = arguments[1] || { },
|
||||
scrollOffsets = document.viewport.getScrollOffsets(),
|
||||
elementOffsets = $(element).cumulativeOffset(),
|
||||
max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();
|
||||
scrollOffsets = document.viewport.getScrollOffsets(),
|
||||
elementOffsets = $(element).cumulativeOffset();
|
||||
|
||||
if (options.offset) elementOffsets[1] += options.offset;
|
||||
|
||||
return new Effect.Tween(null,
|
||||
scrollOffsets.top,
|
||||
elementOffsets[1] > max ? max : elementOffsets[1],
|
||||
elementOffsets[1],
|
||||
options,
|
||||
function(p){ scrollTo(scrollOffsets.left, p.round()) }
|
||||
function(p){ scrollTo(scrollOffsets.left, p.round()); }
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -529,9 +535,9 @@ Effect.Fade = function(element) {
|
|||
var options = Object.extend({
|
||||
from: element.getOpacity() || 1.0,
|
||||
to: 0.0,
|
||||
afterFinishInternal: function(effect) {
|
||||
afterFinishInternal: function(effect) {
|
||||
if (effect.options.to!=0) return;
|
||||
effect.element.hide().setStyle({opacity: oldOpacity});
|
||||
effect.element.hide().setStyle({opacity: oldOpacity});
|
||||
}
|
||||
}, arguments[1] || { });
|
||||
return new Effect.Opacity(element,options);
|
||||
|
@ -547,15 +553,15 @@ Effect.Appear = function(element) {
|
|||
effect.element.forceRerendering();
|
||||
},
|
||||
beforeSetup: function(effect) {
|
||||
effect.element.setOpacity(effect.options.from).show();
|
||||
effect.element.setOpacity(effect.options.from).show();
|
||||
}}, arguments[1] || { });
|
||||
return new Effect.Opacity(element,options);
|
||||
};
|
||||
|
||||
Effect.Puff = function(element) {
|
||||
element = $(element);
|
||||
var oldStyle = {
|
||||
opacity: element.getInlineOpacity(),
|
||||
var oldStyle = {
|
||||
opacity: element.getInlineOpacity(),
|
||||
position: element.getStyle('position'),
|
||||
top: element.style.top,
|
||||
left: element.style.left,
|
||||
|
@ -563,12 +569,12 @@ Effect.Puff = function(element) {
|
|||
height: element.style.height
|
||||
};
|
||||
return new Effect.Parallel(
|
||||
[ new Effect.Scale(element, 200,
|
||||
{ sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
|
||||
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
|
||||
Object.extend({ duration: 1.0,
|
||||
[ new Effect.Scale(element, 200,
|
||||
{ sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
|
||||
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
|
||||
Object.extend({ duration: 1.0,
|
||||
beforeSetupInternal: function(effect) {
|
||||
Position.absolutize(effect.effects[0].element)
|
||||
Position.absolutize(effect.effects[0].element);
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.effects[0].element.hide().setStyle(oldStyle); }
|
||||
|
@ -580,12 +586,12 @@ Effect.BlindUp = function(element) {
|
|||
element = $(element);
|
||||
element.makeClipping();
|
||||
return new Effect.Scale(element, 0,
|
||||
Object.extend({ scaleContent: false,
|
||||
scaleX: false,
|
||||
Object.extend({ scaleContent: false,
|
||||
scaleX: false,
|
||||
restoreAfterFinish: true,
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.element.hide().undoClipping();
|
||||
}
|
||||
}
|
||||
}, arguments[1] || { })
|
||||
);
|
||||
};
|
||||
|
@ -593,15 +599,15 @@ Effect.BlindUp = function(element) {
|
|||
Effect.BlindDown = function(element) {
|
||||
element = $(element);
|
||||
var elementDimensions = element.getDimensions();
|
||||
return new Effect.Scale(element, 100, Object.extend({
|
||||
scaleContent: false,
|
||||
return new Effect.Scale(element, 100, Object.extend({
|
||||
scaleContent: false,
|
||||
scaleX: false,
|
||||
scaleFrom: 0,
|
||||
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
|
||||
restoreAfterFinish: true,
|
||||
afterSetup: function(effect) {
|
||||
effect.element.makeClipping().setStyle({height: '0px'}).show();
|
||||
},
|
||||
effect.element.makeClipping().setStyle({height: '0px'}).show();
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.element.undoClipping();
|
||||
}
|
||||
|
@ -616,16 +622,16 @@ Effect.SwitchOff = function(element) {
|
|||
from: 0,
|
||||
transition: Effect.Transitions.flicker,
|
||||
afterFinishInternal: function(effect) {
|
||||
new Effect.Scale(effect.element, 1, {
|
||||
new Effect.Scale(effect.element, 1, {
|
||||
duration: 0.3, scaleFromCenter: true,
|
||||
scaleX: false, scaleContent: false, restoreAfterFinish: true,
|
||||
beforeSetup: function(effect) {
|
||||
beforeSetup: function(effect) {
|
||||
effect.element.makePositioned().makeClipping();
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}, arguments[1] || { }));
|
||||
};
|
||||
|
@ -637,16 +643,16 @@ Effect.DropOut = function(element) {
|
|||
left: element.getStyle('left'),
|
||||
opacity: element.getInlineOpacity() };
|
||||
return new Effect.Parallel(
|
||||
[ new Effect.Move(element, {x: 0, y: 100, sync: true }),
|
||||
[ new Effect.Move(element, {x: 0, y: 100, sync: true }),
|
||||
new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
|
||||
Object.extend(
|
||||
{ duration: 0.5,
|
||||
beforeSetup: function(effect) {
|
||||
effect.effects[0].element.makePositioned();
|
||||
effect.effects[0].element.makePositioned();
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
|
||||
}
|
||||
}
|
||||
}, arguments[1] || { }));
|
||||
};
|
||||
|
||||
|
@ -674,7 +680,7 @@ Effect.Shake = function(element) {
|
|||
new Effect.Move(effect.element,
|
||||
{ x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
|
||||
effect.element.undoPositioned().setStyle(oldStyle);
|
||||
}}) }}) }}) }}) }}) }});
|
||||
}}); }}); }}); }}); }}); }});
|
||||
};
|
||||
|
||||
Effect.SlideDown = function(element) {
|
||||
|
@ -682,9 +688,9 @@ Effect.SlideDown = function(element) {
|
|||
// SlideDown need to have the content of the element wrapped in a container element with fixed height!
|
||||
var oldInnerBottom = element.down().getStyle('bottom');
|
||||
var elementDimensions = element.getDimensions();
|
||||
return new Effect.Scale(element, 100, Object.extend({
|
||||
scaleContent: false,
|
||||
scaleX: false,
|
||||
return new Effect.Scale(element, 100, Object.extend({
|
||||
scaleContent: false,
|
||||
scaleX: false,
|
||||
scaleFrom: window.opera ? 0 : 1,
|
||||
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
|
||||
restoreAfterFinish: true,
|
||||
|
@ -692,11 +698,11 @@ Effect.SlideDown = function(element) {
|
|||
effect.element.makePositioned();
|
||||
effect.element.down().makePositioned();
|
||||
if (window.opera) effect.element.setStyle({top: ''});
|
||||
effect.element.makeClipping().setStyle({height: '0px'}).show();
|
||||
effect.element.makeClipping().setStyle({height: '0px'}).show();
|
||||
},
|
||||
afterUpdateInternal: function(effect) {
|
||||
effect.element.down().setStyle({bottom:
|
||||
(effect.dims[0] - effect.element.clientHeight) + 'px' });
|
||||
(effect.dims[0] - effect.element.clientHeight) + 'px' });
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.element.undoClipping().undoPositioned();
|
||||
|
@ -710,8 +716,8 @@ Effect.SlideUp = function(element) {
|
|||
var oldInnerBottom = element.down().getStyle('bottom');
|
||||
var elementDimensions = element.getDimensions();
|
||||
return new Effect.Scale(element, window.opera ? 0 : 1,
|
||||
Object.extend({ scaleContent: false,
|
||||
scaleX: false,
|
||||
Object.extend({ scaleContent: false,
|
||||
scaleX: false,
|
||||
scaleMode: 'box',
|
||||
scaleFrom: 100,
|
||||
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
|
||||
|
@ -721,7 +727,7 @@ Effect.SlideUp = function(element) {
|
|||
effect.element.down().makePositioned();
|
||||
if (window.opera) effect.element.setStyle({top: ''});
|
||||
effect.element.makeClipping().show();
|
||||
},
|
||||
},
|
||||
afterUpdateInternal: function(effect) {
|
||||
effect.element.down().setStyle({bottom:
|
||||
(effect.dims[0] - effect.element.clientHeight) + 'px' });
|
||||
|
@ -734,15 +740,15 @@ Effect.SlideUp = function(element) {
|
|||
);
|
||||
};
|
||||
|
||||
// Bug in opera makes the TD containing this element expand for a instance after finish
|
||||
// Bug in opera makes the TD containing this element expand for a instance after finish
|
||||
Effect.Squish = function(element) {
|
||||
return new Effect.Scale(element, window.opera ? 1 : 0, {
|
||||
return new Effect.Scale(element, window.opera ? 1 : 0, {
|
||||
restoreAfterFinish: true,
|
||||
beforeSetup: function(effect) {
|
||||
effect.element.makeClipping();
|
||||
},
|
||||
effect.element.makeClipping();
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.element.hide().undoClipping();
|
||||
effect.element.hide().undoClipping();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -762,13 +768,13 @@ Effect.Grow = function(element) {
|
|||
width: element.style.width,
|
||||
opacity: element.getInlineOpacity() };
|
||||
|
||||
var dims = element.getDimensions();
|
||||
var dims = element.getDimensions();
|
||||
var initialMoveX, initialMoveY;
|
||||
var moveX, moveY;
|
||||
|
||||
|
||||
switch (options.direction) {
|
||||
case 'top-left':
|
||||
initialMoveX = initialMoveY = moveX = moveY = 0;
|
||||
initialMoveX = initialMoveY = moveX = moveY = 0;
|
||||
break;
|
||||
case 'top-right':
|
||||
initialMoveX = dims.width;
|
||||
|
@ -793,11 +799,11 @@ Effect.Grow = function(element) {
|
|||
moveY = -dims.height / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return new Effect.Move(element, {
|
||||
x: initialMoveX,
|
||||
y: initialMoveY,
|
||||
duration: 0.01,
|
||||
duration: 0.01,
|
||||
beforeSetup: function(effect) {
|
||||
effect.element.hide().makeClipping().makePositioned();
|
||||
},
|
||||
|
@ -806,17 +812,17 @@ Effect.Grow = function(element) {
|
|||
[ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
|
||||
new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
|
||||
new Effect.Scale(effect.element, 100, {
|
||||
scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
|
||||
scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
|
||||
sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
|
||||
], Object.extend({
|
||||
beforeSetup: function(effect) {
|
||||
effect.effects[0].element.setStyle({height: '0px'}).show();
|
||||
effect.effects[0].element.setStyle({height: '0px'}).show();
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
|
||||
effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
|
||||
}
|
||||
}, options)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -838,7 +844,7 @@ Effect.Shrink = function(element) {
|
|||
|
||||
var dims = element.getDimensions();
|
||||
var moveX, moveY;
|
||||
|
||||
|
||||
switch (options.direction) {
|
||||
case 'top-left':
|
||||
moveX = moveY = 0;
|
||||
|
@ -855,19 +861,19 @@ Effect.Shrink = function(element) {
|
|||
moveX = dims.width;
|
||||
moveY = dims.height;
|
||||
break;
|
||||
case 'center':
|
||||
case 'center':
|
||||
moveX = dims.width / 2;
|
||||
moveY = dims.height / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return new Effect.Parallel(
|
||||
[ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
|
||||
new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
|
||||
new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
|
||||
], Object.extend({
|
||||
], Object.extend({
|
||||
beforeStartInternal: function(effect) {
|
||||
effect.effects[0].element.makePositioned().makeClipping();
|
||||
effect.effects[0].element.makePositioned().makeClipping();
|
||||
},
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
|
||||
|
@ -877,12 +883,14 @@ Effect.Shrink = function(element) {
|
|||
|
||||
Effect.Pulsate = function(element) {
|
||||
element = $(element);
|
||||
var options = arguments[1] || { };
|
||||
var oldOpacity = element.getInlineOpacity();
|
||||
var transition = options.transition || Effect.Transitions.sinoidal;
|
||||
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
|
||||
reverser.bind(transition);
|
||||
return new Effect.Opacity(element,
|
||||
var options = arguments[1] || { },
|
||||
oldOpacity = element.getInlineOpacity(),
|
||||
transition = options.transition || Effect.Transitions.linear,
|
||||
reverser = function(pos){
|
||||
return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
|
||||
};
|
||||
|
||||
return new Effect.Opacity(element,
|
||||
Object.extend(Object.extend({ duration: 2.0, from: 0,
|
||||
afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
|
||||
}, options), {transition: reverser}));
|
||||
|
@ -896,12 +904,12 @@ Effect.Fold = function(element) {
|
|||
width: element.style.width,
|
||||
height: element.style.height };
|
||||
element.makeClipping();
|
||||
return new Effect.Scale(element, 5, Object.extend({
|
||||
return new Effect.Scale(element, 5, Object.extend({
|
||||
scaleContent: false,
|
||||
scaleX: false,
|
||||
afterFinishInternal: function(effect) {
|
||||
new Effect.Scale(element, 1, {
|
||||
scaleContent: false,
|
||||
new Effect.Scale(element, 1, {
|
||||
scaleContent: false,
|
||||
scaleY: false,
|
||||
afterFinishInternal: function(effect) {
|
||||
effect.element.hide().undoClipping().setStyle(oldStyle);
|
||||
|
@ -916,7 +924,7 @@ Effect.Morph = Class.create(Effect.Base, {
|
|||
var options = Object.extend({
|
||||
style: { }
|
||||
}, arguments[1] || { });
|
||||
|
||||
|
||||
if (!Object.isString(options.style)) this.style = $H(options.style);
|
||||
else {
|
||||
if (options.style.include(':'))
|
||||
|
@ -934,18 +942,18 @@ Effect.Morph = Class.create(Effect.Base, {
|
|||
effect.transforms.each(function(transform) {
|
||||
effect.element.style[transform.style] = '';
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
this.start(options);
|
||||
},
|
||||
|
||||
|
||||
setup: function(){
|
||||
function parseColor(color){
|
||||
if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
|
||||
color = color.parseColor();
|
||||
return $R(0,2).map(function(i){
|
||||
return parseInt( color.slice(i*2+1,i*2+3), 16 )
|
||||
return parseInt( color.slice(i*2+1,i*2+3), 16 );
|
||||
});
|
||||
}
|
||||
this.transforms = this.style.map(function(pair){
|
||||
|
@ -965,9 +973,9 @@ Effect.Morph = Class.create(Effect.Base, {
|
|||
}
|
||||
|
||||
var originalValue = this.element.getStyle(property);
|
||||
return {
|
||||
style: property.camelize(),
|
||||
originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
|
||||
return {
|
||||
style: property.camelize(),
|
||||
originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
|
||||
targetValue: unit=='color' ? parseColor(value) : value,
|
||||
unit: unit
|
||||
};
|
||||
|
@ -978,13 +986,13 @@ Effect.Morph = Class.create(Effect.Base, {
|
|||
transform.unit != 'color' &&
|
||||
(isNaN(transform.originalValue) || isNaN(transform.targetValue))
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
},
|
||||
update: function(position) {
|
||||
var style = { }, transform, i = this.transforms.length;
|
||||
while(i--)
|
||||
style[(transform = this.transforms[i]).style] =
|
||||
style[(transform = this.transforms[i]).style] =
|
||||
transform.unit=='color' ? '#'+
|
||||
(Math.round(transform.originalValue[0]+
|
||||
(transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
|
||||
|
@ -993,7 +1001,7 @@ Effect.Morph = Class.create(Effect.Base, {
|
|||
(Math.round(transform.originalValue[2]+
|
||||
(transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
|
||||
(transform.originalValue +
|
||||
(transform.targetValue - transform.originalValue) * position).toFixed(3) +
|
||||
(transform.targetValue - transform.originalValue) * position).toFixed(3) +
|
||||
(transform.unit === null ? '' : transform.unit);
|
||||
this.element.setStyle(style, true);
|
||||
}
|
||||
|
@ -1030,7 +1038,7 @@ Effect.Transform = Class.create({
|
|||
});
|
||||
|
||||
Element.CSS_PROPERTIES = $w(
|
||||
'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
|
||||
'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
|
||||
'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
|
||||
'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
|
||||
'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
|
||||
|
@ -1039,7 +1047,7 @@ Element.CSS_PROPERTIES = $w(
|
|||
'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
|
||||
'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
|
||||
'right textIndent top width wordSpacing zIndex');
|
||||
|
||||
|
||||
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
|
||||
|
||||
String.__parseStyleElement = document.createElement('div');
|
||||
|
@ -1051,11 +1059,11 @@ String.prototype.parseStyle = function(){
|
|||
String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
|
||||
style = String.__parseStyleElement.childNodes[0].style;
|
||||
}
|
||||
|
||||
|
||||
Element.CSS_PROPERTIES.each(function(property){
|
||||
if (style[property]) styleRules.set(property, style[property]);
|
||||
if (style[property]) styleRules.set(property, style[property]);
|
||||
});
|
||||
|
||||
|
||||
if (Prototype.Browser.IE && this.include('opacity'))
|
||||
styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
|
||||
|
||||
|
@ -1074,14 +1082,14 @@ if (document.defaultView && document.defaultView.getComputedStyle) {
|
|||
Element.getStyles = function(element) {
|
||||
element = $(element);
|
||||
var css = element.currentStyle, styles;
|
||||
styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
|
||||
hash.set(property, css[property]);
|
||||
return hash;
|
||||
styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
|
||||
results[property] = css[property];
|
||||
return results;
|
||||
});
|
||||
if (!styles.opacity) styles.set('opacity', element.getOpacity());
|
||||
if (!styles.opacity) styles.opacity = element.getOpacity();
|
||||
return styles;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Effect.Methods = {
|
||||
morph: function(element, style) {
|
||||
|
@ -1090,7 +1098,7 @@ Effect.Methods = {
|
|||
return element;
|
||||
},
|
||||
visualEffect: function(element, effect, options) {
|
||||
element = $(element)
|
||||
element = $(element);
|
||||
var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
|
||||
new Effect[klass](element, options);
|
||||
return element;
|
||||
|
@ -1104,17 +1112,17 @@ Effect.Methods = {
|
|||
|
||||
$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
|
||||
'pulsate shake puff squish switchOff dropOut').each(
|
||||
function(effect) {
|
||||
function(effect) {
|
||||
Effect.Methods[effect] = function(element, options){
|
||||
element = $(element);
|
||||
Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
|
||||
return element;
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
|
||||
$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
|
||||
function(f) { Effect.Methods[f] = Element[f]; }
|
||||
);
|
||||
|
||||
Element.addMethods(Effect.Methods);
|
||||
Element.addMethods(Effect.Methods);
|
629
public/javascripts/prototype.js
vendored
629
public/javascripts/prototype.js
vendored
File diff suppressed because it is too large
Load diff
3
script/dbconsole
Executable file
3
script/dbconsole
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env ruby
|
||||
require File.dirname(__FILE__) + '/../config/boot'
|
||||
require 'commands/dbconsole'
|
3
script/performance/request
Executable file
3
script/performance/request
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env ruby
|
||||
require File.dirname(__FILE__) + '/../../config/boot'
|
||||
require 'commands/performance/request'
|
3
script/process/inspector
Executable file
3
script/process/inspector
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env ruby
|
||||
require File.dirname(__FILE__) + '/../../config/boot'
|
||||
require 'commands/process/inspector'
|
148
vendor/gems/composite_primary_keys-1.1.0/History.txt
vendored
148
vendor/gems/composite_primary_keys-1.1.0/History.txt
vendored
|
@ -1,148 +0,0 @@
|
|||
== 1.1.0 2008-10-29
|
||||
|
||||
* fixes to get cpk working for Rails 2.1.2
|
||||
|
||||
== 1.0.10 2008-10-22
|
||||
|
||||
* add composite key where clause creator method [timurv]
|
||||
|
||||
== 1.0.9 2008-09-08
|
||||
|
||||
* fix postgres tests
|
||||
* fix for delete_records when has_many association has composite keys [darxriggs]
|
||||
* more consistent table/column name quoting [pbrant]
|
||||
|
||||
== 1.0.8 2008-08-27
|
||||
|
||||
* fix has_many :through for non composite models [thx rcarver]
|
||||
|
||||
== 1.0.7 2008-08-12
|
||||
|
||||
* fix for the last fix -- when has_many is composite and belongs_to is single
|
||||
|
||||
== 1.0.6 2008-08-06
|
||||
|
||||
* fix associations create
|
||||
|
||||
== 1.0.5 2008-07-25
|
||||
|
||||
* fix for calculations with a group by clause [thx Sirius Black]
|
||||
|
||||
== 1.0.4 2008-07-15
|
||||
|
||||
* support for oracle_enhanced adapter [thx Raimonds Simanovskis]
|
||||
|
||||
== 1.0.3 2008-07-13
|
||||
|
||||
* more fixes and tests for has many through [thx Menno van der Sman]
|
||||
|
||||
== 1.0.2 2008-06-07
|
||||
|
||||
* fix for has many through when through association has composite keys
|
||||
|
||||
== 1.0.1 2008-06-06
|
||||
|
||||
* Oracle fixes
|
||||
|
||||
== 1.0.0 2008-06-05
|
||||
|
||||
* Support for Rails 2.1
|
||||
|
||||
== 0.9.93 2008-06-01
|
||||
|
||||
* set fixed dependency on activerecord 2.0.2
|
||||
|
||||
== 0.9.92 2008-02-22
|
||||
|
||||
* Support for has_and_belongs_to_many
|
||||
|
||||
== 0.9.91 2008-01-27
|
||||
|
||||
* Incremented activerecord dependency to 2.0.2 [thx emmanuel.pirsch]
|
||||
|
||||
== 0.9.90 2008-01-27
|
||||
|
||||
* Trial release for rails/activerecord 2.0.2 supported
|
||||
|
||||
== 0.9.1 2007-10-28
|
||||
|
||||
* Migrations fix - allow :primary_key => [:name] to work [no unit test] [thx Shugo Maeda]
|
||||
|
||||
== 0.9.0 2007-09-28
|
||||
|
||||
* Added support for polymorphs [thx nerdrew]
|
||||
* init.rb file so gem can be installed as a plugin for Rails [thx nerdrew]
|
||||
* Added ibm_db support [thx K Venkatasubramaniyan]
|
||||
* Support for cleaning dependents [thx K Venkatasubramaniyan]
|
||||
* Rafactored db rake tasks into namespaces
|
||||
* Added namespaced tests (e.g. mysql:test for test_mysql)
|
||||
|
||||
== 0.8.6 / 2007-6-12
|
||||
|
||||
* 1 emergency fix due to Rails Core change
|
||||
* Rails v7004 removed #quote; fixed with connection.quote_column_name [thx nerdrew]
|
||||
|
||||
== 0.8.5 / 2007-6-5
|
||||
|
||||
* 1 change due to Rails Core change
|
||||
* Can no longer use RAILS_CONNECTION_ADAPTERS from Rails core
|
||||
* 7 dev improvement:
|
||||
* Changed History.txt syntax to rdoc format
|
||||
* Added deploy tasks
|
||||
* Removed CHANGELOG + migrated into History.txt
|
||||
* Changed PKG_NAME -> GEM_NAME in Rakefile
|
||||
* Renamed README -> README.txt for :publish_docs task
|
||||
* Added :check_version task
|
||||
* VER => VERS in rakefile
|
||||
* 1 website improvement:
|
||||
* website/index.txt includes link to "8 steps to fix other ppls code"
|
||||
|
||||
== 0.8.4 / 2007-5-3
|
||||
|
||||
* 1 bugfix
|
||||
* Corrected ids_list => ids in the exception message. That'll teach me for not adding unit tests before fixing bugs.
|
||||
|
||||
== 0.8.3 / 2007-5-3
|
||||
|
||||
* 1 bugfix
|
||||
* Explicit reference to ::ActiveRecord::RecordNotFound
|
||||
* 1 website addition:
|
||||
* Added routing help [Pete Sumskas]
|
||||
|
||||
== 0.8.2 / 2007-4-11
|
||||
|
||||
* 1 major enhancement:
|
||||
* Oracle unit tests!! [Darrin Holst]
|
||||
* And they work too
|
||||
|
||||
== 0.8.1 / 2007-4-10
|
||||
|
||||
* 1 bug fix:
|
||||
* Fixed the distinct(count) for oracle (removed 'as')
|
||||
|
||||
== 0.8.0 / 2007-4-6
|
||||
|
||||
* 1 major enhancement:
|
||||
* Support for calcualtions on associations
|
||||
* 2 new DB supported:
|
||||
* Tests run on sqlite
|
||||
* Tests run on postgresql
|
||||
* History.txt to keep track of changes like these
|
||||
* Using Hoe for Rakefile
|
||||
* Website generator rake tasks
|
||||
|
||||
== 0.3.3
|
||||
* id=
|
||||
* create now work
|
||||
|
||||
== 0.1.4
|
||||
* it was important that #{primary_key} for composites --> 'key1,key2' and not 'key1key2' so created PrimaryKeys class
|
||||
|
||||
== 0.0.1
|
||||
* Initial version
|
||||
* set_primary_keys(*keys) is the activation class method to transform an ActiveRecord into a composite primary key AR
|
||||
* find(*ids) supports the passing of
|
||||
* id sets: Foo.find(2,1),
|
||||
* lists of id sets: Foo.find([2,1], [7,3], [8,12]),
|
||||
* and even stringified versions of the above:
|
||||
* Foo.find '2,1' or Foo.find '2,1;7,3'
|
|
@ -1,121 +0,0 @@
|
|||
History.txt
|
||||
Manifest.txt
|
||||
README.txt
|
||||
README_DB2.txt
|
||||
Rakefile
|
||||
init.rb
|
||||
install.rb
|
||||
lib/adapter_helper/base.rb
|
||||
lib/adapter_helper/mysql.rb
|
||||
lib/adapter_helper/oracle.rb
|
||||
lib/adapter_helper/postgresql.rb
|
||||
lib/adapter_helper/sqlite3.rb
|
||||
lib/composite_primary_keys.rb
|
||||
lib/composite_primary_keys/association_preload.rb
|
||||
lib/composite_primary_keys/associations.rb
|
||||
lib/composite_primary_keys/attribute_methods.rb
|
||||
lib/composite_primary_keys/base.rb
|
||||
lib/composite_primary_keys/calculations.rb
|
||||
lib/composite_primary_keys/composite_arrays.rb
|
||||
lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb
|
||||
lib/composite_primary_keys/connection_adapters/oracle_adapter.rb
|
||||
lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb
|
||||
lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb
|
||||
lib/composite_primary_keys/fixtures.rb
|
||||
lib/composite_primary_keys/migration.rb
|
||||
lib/composite_primary_keys/reflection.rb
|
||||
lib/composite_primary_keys/version.rb
|
||||
loader.rb
|
||||
local/database_connections.rb.sample
|
||||
local/paths.rb.sample
|
||||
local/tasks.rb.sample
|
||||
scripts/console.rb
|
||||
scripts/txt2html
|
||||
scripts/txt2js
|
||||
tasks/activerecord_selection.rake
|
||||
tasks/databases.rake
|
||||
tasks/databases/mysql.rake
|
||||
tasks/databases/oracle.rake
|
||||
tasks/databases/postgresql.rake
|
||||
tasks/databases/sqlite3.rake
|
||||
tasks/deployment.rake
|
||||
tasks/local_setup.rake
|
||||
tasks/website.rake
|
||||
test/README_tests.txt
|
||||
test/abstract_unit.rb
|
||||
test/connections/native_ibm_db/connection.rb
|
||||
test/connections/native_mysql/connection.rb
|
||||
test/connections/native_oracle/connection.rb
|
||||
test/connections/native_postgresql/connection.rb
|
||||
test/connections/native_sqlite/connection.rb
|
||||
test/fixtures/article.rb
|
||||
test/fixtures/articles.yml
|
||||
test/fixtures/comment.rb
|
||||
test/fixtures/comments.yml
|
||||
test/fixtures/db_definitions/db2-create-tables.sql
|
||||
test/fixtures/db_definitions/db2-drop-tables.sql
|
||||
test/fixtures/db_definitions/mysql.sql
|
||||
test/fixtures/db_definitions/oracle.drop.sql
|
||||
test/fixtures/db_definitions/oracle.sql
|
||||
test/fixtures/db_definitions/postgresql.sql
|
||||
test/fixtures/db_definitions/sqlite.sql
|
||||
test/fixtures/department.rb
|
||||
test/fixtures/departments.yml
|
||||
test/fixtures/employee.rb
|
||||
test/fixtures/employees.yml
|
||||
test/fixtures/group.rb
|
||||
test/fixtures/groups.yml
|
||||
test/fixtures/hack.rb
|
||||
test/fixtures/hacks.yml
|
||||
test/fixtures/membership.rb
|
||||
test/fixtures/membership_status.rb
|
||||
test/fixtures/membership_statuses.yml
|
||||
test/fixtures/memberships.yml
|
||||
test/fixtures/product.rb
|
||||
test/fixtures/product_tariff.rb
|
||||
test/fixtures/product_tariffs.yml
|
||||
test/fixtures/products.yml
|
||||
test/fixtures/reading.rb
|
||||
test/fixtures/readings.yml
|
||||
test/fixtures/reference_code.rb
|
||||
test/fixtures/reference_codes.yml
|
||||
test/fixtures/reference_type.rb
|
||||
test/fixtures/reference_types.yml
|
||||
test/fixtures/street.rb
|
||||
test/fixtures/streets.yml
|
||||
test/fixtures/suburb.rb
|
||||
test/fixtures/suburbs.yml
|
||||
test/fixtures/tariff.rb
|
||||
test/fixtures/tariffs.yml
|
||||
test/fixtures/user.rb
|
||||
test/fixtures/users.yml
|
||||
test/hash_tricks.rb
|
||||
test/plugins/pagination.rb
|
||||
test/plugins/pagination_helper.rb
|
||||
test/test_associations.rb
|
||||
test/test_attribute_methods.rb
|
||||
test/test_attributes.rb
|
||||
test/test_clone.rb
|
||||
test/test_composite_arrays.rb
|
||||
test/test_create.rb
|
||||
test/test_delete.rb
|
||||
test/test_dummy.rb
|
||||
test/test_find.rb
|
||||
test/test_ids.rb
|
||||
test/test_miscellaneous.rb
|
||||
test/test_pagination.rb
|
||||
test/test_polymorphic.rb
|
||||
test/test_santiago.rb
|
||||
test/test_tutorial_examle.rb
|
||||
test/test_update.rb
|
||||
tmp/test.db
|
||||
website/index.html
|
||||
website/index.txt
|
||||
website/javascripts/rounded_corners_lite.inc.js
|
||||
website/stylesheets/screen.css
|
||||
website/template.js
|
||||
website/template.rhtml
|
||||
website/version-raw.js
|
||||
website/version-raw.txt
|
||||
website/version.js
|
||||
website/version.txt
|
|
@ -1,41 +0,0 @@
|
|||
= Composite Primary Keys for ActiveRecords
|
||||
|
||||
== Summary
|
||||
|
||||
ActiveRecords/Rails famously doesn't support composite primary keys.
|
||||
This RubyGem extends the activerecord gem to provide CPK support.
|
||||
|
||||
== Installation
|
||||
|
||||
gem install composite_primary_keys
|
||||
|
||||
== Usage
|
||||
|
||||
require 'composite_primary_keys'
|
||||
class ProductVariation
|
||||
set_primary_keys :product_id, :variation_seq
|
||||
end
|
||||
|
||||
pv = ProductVariation.find(345, 12)
|
||||
|
||||
It even supports composite foreign keys for associations.
|
||||
|
||||
See http://compositekeys.rubyforge.org for more.
|
||||
|
||||
== Running Tests
|
||||
|
||||
See test/README.tests.txt
|
||||
|
||||
== Url
|
||||
|
||||
http://compositekeys.rubyforge.org
|
||||
|
||||
== Questions, Discussion and Contributions
|
||||
|
||||
http://groups.google.com/compositekeys
|
||||
|
||||
== Author
|
||||
|
||||
Written by Dr Nic Williams, drnicwilliams@gmail
|
||||
Contributions by many!
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
Composite Primary key support for db2
|
||||
|
||||
== Driver Support ==
|
||||
|
||||
DB2 support requires the IBM_DB driver provided by http://rubyforge.org/projects/rubyibm/
|
||||
project. Install using gem install ibm_db. Tested against version 0.60 of the driver.
|
||||
This rubyforge project appears to be permenant location for the IBM adapter.
|
||||
Older versions of the driver available from IBM Alphaworks will not work.
|
||||
|
||||
== Driver Bug and workaround provided as part of this plugin ==
|
||||
|
||||
Unlike the basic quote routine available for Rails AR, the DB2 adapter's quote
|
||||
method doesn't return " column_name = 1 " when string values (integers in string type variable)
|
||||
are passed for quoting numeric column. Rather it returns "column_name = '1'.
|
||||
DB2 doesn't accept single quoting numeric columns in SQL. Currently, as part of
|
||||
this plugin a fix is provided for the DB2 adapter since this plugin does
|
||||
pass string values like this. Perhaps a patch should be sent to the DB2 adapter
|
||||
project for a permanant fix.
|
||||
|
||||
== Database Setup ==
|
||||
|
||||
Database must be manually created using a separate command. Read the rake task
|
||||
for creating tables and change the db name, user and passwords accordingly.
|
||||
|
||||
== Tested Database Server version ==
|
||||
|
||||
This is tested against DB2 v9.1 in Ubuntu Feisty Fawn (7.04)
|
||||
|
||||
== Tested Database Client version ==
|
||||
|
||||
This is tested against DB2 v9.1 in Ubuntu Feisty Fawn (7.04)
|
||||
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
require 'rubygems'
|
||||
require 'rake'
|
||||
require 'rake/clean'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
require 'rake/contrib/rubyforgepublisher'
|
||||
require 'fileutils'
|
||||
require 'hoe'
|
||||
include FileUtils
|
||||
require File.join(File.dirname(__FILE__), 'lib', 'composite_primary_keys', 'version')
|
||||
|
||||
AUTHOR = "Dr Nic Williams"
|
||||
EMAIL = "drnicwilliams@gmail.com"
|
||||
DESCRIPTION = "Composite key support for ActiveRecords"
|
||||
GEM_NAME = "composite_primary_keys" # what ppl will type to install your gem
|
||||
if File.exists?("~/.rubyforge/user-config.yml")
|
||||
# TODO this should prob go in a local/ file
|
||||
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
||||
RUBYFORGE_USERNAME = config["username"]
|
||||
end
|
||||
RUBYFORGE_PROJECT = "compositekeys"
|
||||
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
||||
|
||||
REV = nil #File.read(".svn/entries")[/committed-rev="(\d+)"/, 1] rescue nil
|
||||
VERS = ENV['VERSION'] || (CompositePrimaryKeys::VERSION::STRING + (REV ? ".#{REV}" : ""))
|
||||
CLEAN.include ['**/.*.sw?', '*.gem', '.config','debug.log','*.db','logfile','log/**/*','**/.DS_Store', '.project']
|
||||
RDOC_OPTS = ['--quiet', '--title', "newgem documentation",
|
||||
"--opname", "index.html",
|
||||
"--line-numbers",
|
||||
"--main", "README",
|
||||
"--inline-source"]
|
||||
|
||||
class Hoe
|
||||
def extra_deps
|
||||
@extra_deps.reject { |x| Array(x).first == 'hoe' }
|
||||
end
|
||||
end
|
||||
|
||||
# Generate all the Rake tasks
|
||||
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
||||
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
||||
p.author = AUTHOR
|
||||
p.description = DESCRIPTION
|
||||
p.email = EMAIL
|
||||
p.summary = DESCRIPTION
|
||||
p.url = HOMEPATH
|
||||
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
||||
p.test_globs = ["test/**/test*.rb"]
|
||||
p.clean_globs |= CLEAN #An array of file patterns to delete on clean.
|
||||
|
||||
# == Optional
|
||||
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
||||
p.extra_deps = [['activerecord', '>= 2.1.2']] #An array of rubygem dependencies.
|
||||
#p.spec_extras - A hash of extra values to set in the gemspec.
|
||||
end
|
||||
|
||||
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n")
|
||||
PATH = RUBYFORGE_PROJECT
|
||||
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
||||
|
||||
PROJECT_ROOT = File.expand_path(".")
|
||||
|
||||
require 'loader'
|
|
@ -1,2 +0,0 @@
|
|||
# Include hook code here
|
||||
require_dependency 'composite_primary_keys'
|
|
@ -1,30 +0,0 @@
|
|||
require 'rbconfig'
|
||||
require 'find'
|
||||
require 'ftools'
|
||||
|
||||
include Config
|
||||
|
||||
# this was adapted from rdoc's install.rb by ways of Log4r
|
||||
|
||||
$sitedir = CONFIG["sitelibdir"]
|
||||
unless $sitedir
|
||||
version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
|
||||
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
||||
$sitedir = $:.find {|x| x =~ /site_ruby/ }
|
||||
if !$sitedir
|
||||
$sitedir = File.join($libdir, "site_ruby")
|
||||
elsif $sitedir !~ Regexp.quote(version)
|
||||
$sitedir = File.join($sitedir, version)
|
||||
end
|
||||
end
|
||||
|
||||
# the acual gruntwork
|
||||
Dir.chdir("lib")
|
||||
|
||||
Find.find("composite_primary_keys", "composite_primary_keys.rb") { |f|
|
||||
if f[-3..-1] == ".rb"
|
||||
File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
|
||||
else
|
||||
File::makedirs(File.join($sitedir, *f.split(/\//)))
|
||||
end
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
module AdapterHelper
|
||||
class Base
|
||||
class << self
|
||||
attr_accessor :adapter
|
||||
|
||||
def load_connection_from_env(adapter)
|
||||
self.adapter = adapter
|
||||
unless ENV['cpk_adapters']
|
||||
puts error_msg_setup_helper
|
||||
exit
|
||||
end
|
||||
|
||||
ActiveRecord::Base.configurations = YAML.load(ENV['cpk_adapters'])
|
||||
unless spec = ActiveRecord::Base.configurations[adapter]
|
||||
puts error_msg_adapter_helper
|
||||
exit
|
||||
end
|
||||
spec[:adapter] = adapter
|
||||
spec
|
||||
end
|
||||
|
||||
def error_msg_setup_helper
|
||||
<<-EOS
|
||||
Setup Helper:
|
||||
CPK now has a place for your individual testing configuration.
|
||||
That is, instead of hardcoding it in the Rakefile and test/connections files,
|
||||
there is now a local/database_connections.rb file that is NOT in the
|
||||
repository. Your personal DB information (username, password etc) can
|
||||
be stored here without making it difficult to submit patches etc.
|
||||
|
||||
Installation:
|
||||
i) cp locals/database_connections.rb.sample locals/database_connections.rb
|
||||
ii) For #{adapter} connection details see "Adapter Setup Helper" below.
|
||||
iii) Rerun this task
|
||||
|
||||
#{error_msg_adapter_helper}
|
||||
|
||||
Current ENV:
|
||||
#{ENV.inspect}
|
||||
EOS
|
||||
end
|
||||
|
||||
def error_msg_adapter_helper
|
||||
<<-EOS
|
||||
Adapter Setup Helper:
|
||||
To run #{adapter} tests, you need to setup your #{adapter} connections.
|
||||
In your local/database_connections.rb file, within the ENV['cpk_adapter'] hash, add:
|
||||
"#{adapter}" => { adapter settings }
|
||||
|
||||
That is, it will look like:
|
||||
ENV['cpk_adapters'] = {
|
||||
"#{adapter}" => {
|
||||
:adapter => "#{adapter}",
|
||||
:username => "root",
|
||||
:password => "root",
|
||||
# ...
|
||||
}
|
||||
}.to_yaml
|
||||
EOS
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), 'base')
|
||||
|
||||
module AdapterHelper
|
||||
class MySQL < Base
|
||||
class << self
|
||||
def load_connection_from_env
|
||||
spec = super('mysql')
|
||||
spec[:database] ||= 'composite_primary_keys_unittest'
|
||||
spec
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,12 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), 'base')
|
||||
|
||||
module AdapterHelper
|
||||
class Oracle < Base
|
||||
class << self
|
||||
def load_connection_from_env
|
||||
spec = super('oracle')
|
||||
spec
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), 'base')
|
||||
|
||||
module AdapterHelper
|
||||
class Postgresql < Base
|
||||
class << self
|
||||
def load_connection_from_env
|
||||
spec = super('postgresql')
|
||||
spec[:database] ||= 'composite_primary_keys_unittest'
|
||||
spec
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), 'base')
|
||||
|
||||
module AdapterHelper
|
||||
class Sqlite3 < Base
|
||||
class << self
|
||||
def load_connection_from_env
|
||||
spec = super('sqlite3')
|
||||
spec[:dbfile] ||= "tmp/test.db"
|
||||
spec
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,55 +0,0 @@
|
|||
#--
|
||||
# Copyright (c) 2006 Nic Williams
|
||||
#
|
||||
# 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.
|
||||
#++
|
||||
|
||||
$:.unshift(File.dirname(__FILE__)) unless
|
||||
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
||||
|
||||
unless defined?(ActiveRecord)
|
||||
begin
|
||||
require 'active_record'
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
require_gem 'activerecord'
|
||||
end
|
||||
end
|
||||
|
||||
require 'composite_primary_keys/fixtures'
|
||||
require 'composite_primary_keys/composite_arrays'
|
||||
require 'composite_primary_keys/associations'
|
||||
require 'composite_primary_keys/association_preload'
|
||||
require 'composite_primary_keys/reflection'
|
||||
require 'composite_primary_keys/base'
|
||||
require 'composite_primary_keys/calculations'
|
||||
require 'composite_primary_keys/migration'
|
||||
require 'composite_primary_keys/attribute_methods'
|
||||
|
||||
ActiveRecord::Base.class_eval do
|
||||
include CompositePrimaryKeys::ActiveRecord::Base
|
||||
end
|
||||
|
||||
Dir[File.dirname(__FILE__) + '/composite_primary_keys/connection_adapters/*.rb'].each do |adapter|
|
||||
begin
|
||||
require adapter.gsub('.rb','')
|
||||
rescue MissingSourceFile
|
||||
end
|
||||
end
|
|
@ -1,236 +0,0 @@
|
|||
module CompositePrimaryKeys
|
||||
module ActiveRecord
|
||||
module AssociationPreload
|
||||
def self.append_features(base)
|
||||
super
|
||||
base.send(:extend, ClassMethods)
|
||||
end
|
||||
|
||||
# Composite key versions of Association functions
|
||||
module ClassMethods
|
||||
def preload_has_and_belongs_to_many_association(records, reflection, preload_options={})
|
||||
table_name = reflection.klass.quoted_table_name
|
||||
id_to_record_map, ids = construct_id_map(records)
|
||||
records.each {|record| record.send(reflection.name).loaded}
|
||||
options = reflection.options
|
||||
|
||||
if composite?
|
||||
primary_key = reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP)
|
||||
where = (primary_key * ids.size).in_groups_of(primary_key.size).map do |keys|
|
||||
"(" + keys.map{|key| "t0.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
|
||||
end.join(" OR ")
|
||||
|
||||
conditions = [where, ids].flatten
|
||||
joins = "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{full_composite_join_clause(reflection, reflection.klass.table_name, reflection.klass.primary_key, 't0', reflection.association_foreign_key)}"
|
||||
parent_primary_keys = reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP).map{|k| "t0.#{connection.quote_column_name(k)}"}
|
||||
parent_record_id = connection.concat(*parent_primary_keys.zip(["','"] * (parent_primary_keys.size - 1)).flatten.compact)
|
||||
else
|
||||
conditions = ["t0.#{connection.quote_column_name(reflection.primary_key_name)} IN (?)", ids]
|
||||
joins = "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{connection.quote_column_name(reflection.klass.primary_key)} = t0.#{connection.quote_column_name(reflection.association_foreign_key)})"
|
||||
parent_record_id = reflection.primary_key_name
|
||||
end
|
||||
|
||||
conditions.first << append_conditions(reflection, preload_options)
|
||||
|
||||
associated_records = reflection.klass.find(:all,
|
||||
:conditions => conditions,
|
||||
:include => options[:include],
|
||||
:joins => joins,
|
||||
:select => "#{options[:select] || table_name+'.*'}, #{parent_record_id} as parent_record_id_",
|
||||
:order => options[:order])
|
||||
|
||||
set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'parent_record_id_')
|
||||
end
|
||||
|
||||
def preload_has_many_association(records, reflection, preload_options={})
|
||||
id_to_record_map, ids = construct_id_map(records)
|
||||
records.each {|record| record.send(reflection.name).loaded}
|
||||
options = reflection.options
|
||||
|
||||
if options[:through]
|
||||
through_records = preload_through_records(records, reflection, options[:through])
|
||||
through_reflection = reflections[options[:through]]
|
||||
through_primary_key = through_reflection.primary_key_name
|
||||
|
||||
unless through_records.empty?
|
||||
source = reflection.source_reflection.name
|
||||
#add conditions from reflection!
|
||||
through_records.first.class.preload_associations(through_records, source, reflection.options)
|
||||
through_records.each do |through_record|
|
||||
key = through_primary_key.to_s.split(CompositePrimaryKeys::ID_SEP).map{|k| through_record.send(k)}.join(CompositePrimaryKeys::ID_SEP)
|
||||
add_preloaded_records_to_collection(id_to_record_map[key], reflection.name, through_record.send(source))
|
||||
end
|
||||
end
|
||||
else
|
||||
associated_records = find_associated_records(ids, reflection, preload_options)
|
||||
set_association_collection_records(id_to_record_map, reflection.name, associated_records, reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP))
|
||||
end
|
||||
end
|
||||
|
||||
def preload_through_records(records, reflection, through_association)
|
||||
through_reflection = reflections[through_association]
|
||||
through_primary_key = through_reflection.primary_key_name
|
||||
|
||||
if reflection.options[:source_type]
|
||||
interface = reflection.source_reflection.options[:foreign_type]
|
||||
preload_options = {:conditions => ["#{connection.quote_column_name interface} = ?", reflection.options[:source_type]]}
|
||||
|
||||
records.compact!
|
||||
records.first.class.preload_associations(records, through_association, preload_options)
|
||||
|
||||
# Dont cache the association - we would only be caching a subset
|
||||
through_records = []
|
||||
records.each do |record|
|
||||
proxy = record.send(through_association)
|
||||
|
||||
if proxy.respond_to?(:target)
|
||||
through_records << proxy.target
|
||||
proxy.reset
|
||||
else # this is a has_one :through reflection
|
||||
through_records << proxy if proxy
|
||||
end
|
||||
end
|
||||
through_records.flatten!
|
||||
else
|
||||
records.first.class.preload_associations(records, through_association)
|
||||
through_records = records.map {|record| record.send(through_association)}.flatten
|
||||
end
|
||||
|
||||
through_records.compact!
|
||||
through_records
|
||||
end
|
||||
|
||||
def preload_belongs_to_association(records, reflection, preload_options={})
|
||||
options = reflection.options
|
||||
primary_key_name = reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP)
|
||||
|
||||
if options[:polymorphic]
|
||||
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
|
||||
else
|
||||
# I need to keep the original ids for each record (as opposed to the stringified) so
|
||||
# that they get properly converted for each db so the id_map ends up looking like:
|
||||
#
|
||||
# { '1,2' => {:id => [1,2], :records => [...records...]}}
|
||||
id_map = {}
|
||||
|
||||
records.each do |record|
|
||||
key = primary_key_name.map{|k| record.attributes[k]}
|
||||
key_as_string = key.join(CompositePrimaryKeys::ID_SEP)
|
||||
|
||||
if key_as_string
|
||||
mapped_records = (id_map[key_as_string] ||= {:id => key, :records => []})
|
||||
mapped_records[:records] << record
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
klasses_and_ids = [[reflection.klass.name, id_map]]
|
||||
end
|
||||
|
||||
klasses_and_ids.each do |klass_and_id|
|
||||
klass_name, id_map = *klass_and_id
|
||||
klass = klass_name.constantize
|
||||
table_name = klass.quoted_table_name
|
||||
connection = reflection.active_record.connection
|
||||
|
||||
if composite?
|
||||
primary_key = klass.primary_key.to_s.split(CompositePrimaryKeys::ID_SEP)
|
||||
ids = id_map.keys.uniq.map {|id| id_map[id][:id]}
|
||||
|
||||
where = (primary_key * ids.size).in_groups_of(primary_key.size).map do |keys|
|
||||
"(" + keys.map{|key| "#{table_name}.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
|
||||
end.join(" OR ")
|
||||
|
||||
conditions = [where, ids].flatten
|
||||
else
|
||||
conditions = ["#{table_name}.#{connection.quote_column_name(primary_key)} IN (?)", id_map.keys.uniq]
|
||||
end
|
||||
|
||||
conditions.first << append_conditions(reflection, preload_options)
|
||||
|
||||
associated_records = klass.find(:all,
|
||||
:conditions => conditions,
|
||||
:include => options[:include],
|
||||
:select => options[:select],
|
||||
:joins => options[:joins],
|
||||
:order => options[:order])
|
||||
|
||||
set_association_single_records(id_map, reflection.name, associated_records, primary_key)
|
||||
end
|
||||
end
|
||||
|
||||
def set_association_collection_records(id_to_record_map, reflection_name, associated_records, key)
|
||||
associated_records.each do |associated_record|
|
||||
associated_record_key = associated_record[key]
|
||||
associated_record_key = associated_record_key.is_a?(Array) ? associated_record_key.join(CompositePrimaryKeys::ID_SEP) : associated_record_key.to_s
|
||||
mapped_records = id_to_record_map[associated_record_key]
|
||||
add_preloaded_records_to_collection(mapped_records, reflection_name, associated_record)
|
||||
end
|
||||
end
|
||||
|
||||
def set_association_single_records(id_to_record_map, reflection_name, associated_records, key)
|
||||
seen_keys = {}
|
||||
associated_records.each do |associated_record|
|
||||
associated_record_key = associated_record[key]
|
||||
associated_record_key = associated_record_key.is_a?(Array) ? associated_record_key.join(CompositePrimaryKeys::ID_SEP) : associated_record_key.to_s
|
||||
|
||||
#this is a has_one or belongs_to: there should only be one record.
|
||||
#Unfortunately we can't (in portable way) ask the database for 'all records where foo_id in (x,y,z), but please
|
||||
# only one row per distinct foo_id' so this where we enforce that
|
||||
next if seen_keys[associated_record_key]
|
||||
seen_keys[associated_record_key] = true
|
||||
mapped_records = id_to_record_map[associated_record_key][:records]
|
||||
mapped_records.each do |mapped_record|
|
||||
mapped_record.send("set_#{reflection_name}_target", associated_record)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def find_associated_records(ids, reflection, preload_options)
|
||||
options = reflection.options
|
||||
table_name = reflection.klass.quoted_table_name
|
||||
|
||||
if interface = reflection.options[:as]
|
||||
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
|
||||
else
|
||||
connection = reflection.active_record.connection
|
||||
foreign_key = reflection.primary_key_name
|
||||
conditions = ["#{table_name}.#{connection.quote_column_name(foreign_key)} IN (?)", ids]
|
||||
|
||||
if composite?
|
||||
foreign_keys = foreign_key.to_s.split(CompositePrimaryKeys::ID_SEP)
|
||||
|
||||
where = (foreign_keys * ids.size).in_groups_of(foreign_keys.size).map do |keys|
|
||||
"(" + keys.map{|key| "#{table_name}.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
|
||||
end.join(" OR ")
|
||||
|
||||
conditions = [where, ids].flatten
|
||||
end
|
||||
end
|
||||
|
||||
conditions.first << append_conditions(reflection, preload_options)
|
||||
|
||||
reflection.klass.find(:all,
|
||||
:select => (preload_options[:select] || options[:select] || "#{table_name}.*"),
|
||||
:include => preload_options[:include] || options[:include],
|
||||
:conditions => conditions,
|
||||
:joins => options[:joins],
|
||||
:group => preload_options[:group] || options[:group],
|
||||
:order => preload_options[:order] || options[:order])
|
||||
end
|
||||
|
||||
def full_composite_join_clause(reflection, table1, full_keys1, table2, full_keys2)
|
||||
connection = reflection.active_record.connection
|
||||
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
|
||||
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
|
||||
where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
|
||||
quoted1 = connection.quote_table_name(table1)
|
||||
quoted2 = connection.quote_table_name(table2)
|
||||
"#{quoted1}.#{connection.quote_column_name(key_pair.first)}=#{quoted2}.#{connection.quote_column_name(key_pair.last)}"
|
||||
end.join(" AND ")
|
||||
"(#{where_clause})"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,428 +0,0 @@
|
|||
module CompositePrimaryKeys
|
||||
module ActiveRecord
|
||||
module Associations
|
||||
def self.append_features(base)
|
||||
super
|
||||
base.send(:extend, ClassMethods)
|
||||
end
|
||||
|
||||
# Composite key versions of Association functions
|
||||
module ClassMethods
|
||||
|
||||
def construct_counter_sql_with_included_associations(options, join_dependency)
|
||||
scope = scope(:find)
|
||||
sql = "SELECT COUNT(DISTINCT #{quoted_table_columns(primary_key)})"
|
||||
|
||||
# A (slower) workaround if we're using a backend, like sqlite, that doesn't support COUNT DISTINCT.
|
||||
if !self.connection.supports_count_distinct?
|
||||
sql = "SELECT COUNT(*) FROM (SELECT DISTINCT #{quoted_table_columns(primary_key)}"
|
||||
end
|
||||
|
||||
sql << " FROM #{quoted_table_name} "
|
||||
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
|
||||
|
||||
add_joins!(sql, options, scope)
|
||||
add_conditions!(sql, options[:conditions], scope)
|
||||
add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
|
||||
|
||||
add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
|
||||
|
||||
if !self.connection.supports_count_distinct?
|
||||
sql << ")"
|
||||
end
|
||||
|
||||
return sanitize_sql(sql)
|
||||
end
|
||||
|
||||
def construct_finder_sql_with_included_associations(options, join_dependency)
|
||||
scope = scope(:find)
|
||||
sql = "SELECT #{column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
|
||||
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
|
||||
|
||||
add_joins!(sql, options, scope)
|
||||
add_conditions!(sql, options[:conditions], scope)
|
||||
add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && options[:limit]
|
||||
|
||||
sql << "ORDER BY #{options[:order]} " if options[:order]
|
||||
|
||||
add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
|
||||
|
||||
return sanitize_sql(sql)
|
||||
end
|
||||
|
||||
def table_columns(columns)
|
||||
columns.collect {|column| "#{self.quoted_table_name}.#{connection.quote_column_name(column)}"}
|
||||
end
|
||||
|
||||
def quoted_table_columns(columns)
|
||||
table_columns(columns).join(ID_SEP)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveRecord::Associations::ClassMethods
|
||||
class JoinDependency
|
||||
def construct_association(record, join, row)
|
||||
case join.reflection.macro
|
||||
when :has_many, :has_and_belongs_to_many
|
||||
collection = record.send(join.reflection.name)
|
||||
collection.loaded
|
||||
|
||||
join_aliased_primary_keys = join.active_record.composite? ?
|
||||
join.aliased_primary_key : [join.aliased_primary_key]
|
||||
return nil if
|
||||
record.id.to_s != join.parent.record_id(row).to_s or not
|
||||
join_aliased_primary_keys.select {|key| row[key].nil?}.blank?
|
||||
association = join.instantiate(row)
|
||||
collection.target.push(association) unless collection.target.include?(association)
|
||||
when :has_one, :belongs_to
|
||||
return if record.id.to_s != join.parent.record_id(row).to_s or
|
||||
[*join.aliased_primary_key].any? { |key| row[key].nil? }
|
||||
association = join.instantiate(row)
|
||||
record.send("set_#{join.reflection.name}_target", association)
|
||||
else
|
||||
raise ConfigurationError, "unknown macro: #{join.reflection.macro}"
|
||||
end
|
||||
return association
|
||||
end
|
||||
|
||||
class JoinBase
|
||||
def aliased_primary_key
|
||||
active_record.composite? ?
|
||||
primary_key.inject([]) {|aliased_keys, key| aliased_keys << "#{ aliased_prefix }_r#{aliased_keys.length}"} :
|
||||
"#{ aliased_prefix }_r0"
|
||||
end
|
||||
|
||||
def record_id(row)
|
||||
active_record.composite? ?
|
||||
aliased_primary_key.map {|key| row[key]}.to_composite_ids :
|
||||
row[aliased_primary_key]
|
||||
end
|
||||
|
||||
def column_names_with_alias
|
||||
unless @column_names_with_alias
|
||||
@column_names_with_alias = []
|
||||
keys = active_record.composite? ? primary_key.map(&:to_s) : [primary_key]
|
||||
(keys + (column_names - keys)).each_with_index do |column_name, i|
|
||||
@column_names_with_alias << [column_name, "#{ aliased_prefix }_r#{ i }"]
|
||||
end
|
||||
end
|
||||
return @column_names_with_alias
|
||||
end
|
||||
end
|
||||
|
||||
class JoinAssociation < JoinBase
|
||||
alias single_association_join association_join
|
||||
def association_join
|
||||
reflection.active_record.composite? ? composite_association_join : single_association_join
|
||||
end
|
||||
|
||||
def composite_association_join
|
||||
join = case reflection.macro
|
||||
when :has_and_belongs_to_many
|
||||
" LEFT OUTER JOIN %s ON %s " % [
|
||||
table_alias_for(options[:join_table], aliased_join_table_name),
|
||||
composite_join_clause(
|
||||
full_keys(aliased_join_table_name, options[:foreign_key] || reflection.active_record.to_s.classify.foreign_key),
|
||||
full_keys(reflection.active_record.table_name, reflection.active_record.primary_key)
|
||||
)
|
||||
] +
|
||||
" LEFT OUTER JOIN %s ON %s " % [
|
||||
table_name_and_alias,
|
||||
composite_join_clause(
|
||||
full_keys(aliased_table_name, klass.primary_key),
|
||||
full_keys(aliased_join_table_name, options[:association_foreign_key] || klass.table_name.classify.foreign_key)
|
||||
)
|
||||
]
|
||||
when :has_many, :has_one
|
||||
case
|
||||
when reflection.macro == :has_many && reflection.options[:through]
|
||||
through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : ''
|
||||
if through_reflection.options[:as] # has_many :through against a polymorphic join
|
||||
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
|
||||
else
|
||||
if source_reflection.macro == :has_many && source_reflection.options[:as]
|
||||
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
|
||||
else
|
||||
case source_reflection.macro
|
||||
when :belongs_to
|
||||
first_key = primary_key
|
||||
second_key = options[:foreign_key] || klass.to_s.classify.foreign_key
|
||||
when :has_many
|
||||
first_key = through_reflection.klass.to_s.classify.foreign_key
|
||||
second_key = options[:foreign_key] || primary_key
|
||||
end
|
||||
|
||||
" LEFT OUTER JOIN %s ON %s " % [
|
||||
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
|
||||
composite_join_clause(
|
||||
full_keys(aliased_join_table_name, through_reflection.primary_key_name),
|
||||
full_keys(parent.aliased_table_name, parent.primary_key)
|
||||
)
|
||||
] +
|
||||
" LEFT OUTER JOIN %s ON %s " % [
|
||||
table_name_and_alias,
|
||||
composite_join_clause(
|
||||
full_keys(aliased_table_name, first_key),
|
||||
full_keys(aliased_join_table_name, second_key)
|
||||
)
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
when reflection.macro == :has_many && reflection.options[:as]
|
||||
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
|
||||
when reflection.macro == :has_one && reflection.options[:as]
|
||||
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
|
||||
else
|
||||
foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key
|
||||
" LEFT OUTER JOIN %s ON %s " % [
|
||||
table_name_and_alias,
|
||||
composite_join_clause(
|
||||
full_keys(aliased_table_name, foreign_key),
|
||||
full_keys(parent.aliased_table_name, parent.primary_key)),
|
||||
]
|
||||
end
|
||||
when :belongs_to
|
||||
" LEFT OUTER JOIN %s ON %s " % [
|
||||
table_name_and_alias,
|
||||
composite_join_clause(
|
||||
full_keys(aliased_table_name, reflection.klass.primary_key),
|
||||
full_keys(parent.aliased_table_name, options[:foreign_key] || klass.to_s.foreign_key)),
|
||||
]
|
||||
else
|
||||
""
|
||||
end || ''
|
||||
join << %(AND %s.%s = %s ) % [
|
||||
aliased_table_name,
|
||||
reflection.active_record.connection.quote_column_name(reflection.active_record.inheritance_column),
|
||||
klass.connection.quote(klass.name)] unless klass.descends_from_active_record?
|
||||
join << "AND #{interpolate_sql(sanitize_sql(reflection.options[:conditions]))} " if reflection.options[:conditions]
|
||||
join
|
||||
end
|
||||
|
||||
def full_keys(table_name, keys)
|
||||
connection = reflection.active_record.connection
|
||||
quoted_table_name = connection.quote_table_name(table_name)
|
||||
if keys.is_a?(Array)
|
||||
keys.collect {|key| "#{quoted_table_name}.#{connection.quote_column_name(key)}"}.join(CompositePrimaryKeys::ID_SEP)
|
||||
else
|
||||
"#{quoted_table_name}.#{connection.quote_column_name(keys)}"
|
||||
end
|
||||
end
|
||||
|
||||
def composite_join_clause(full_keys1, full_keys2)
|
||||
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
|
||||
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
|
||||
where_clause = [full_keys1, full_keys2].transpose.map do |key1, key2|
|
||||
"#{key1}=#{key2}"
|
||||
end.join(" AND ")
|
||||
"(#{where_clause})"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveRecord::Associations
|
||||
class AssociationProxy #:nodoc:
|
||||
|
||||
def composite_where_clause(full_keys, ids)
|
||||
full_keys = full_keys.split(CompositePrimaryKeys::ID_SEP) if full_keys.is_a?(String)
|
||||
|
||||
if ids.is_a?(String)
|
||||
ids = [[ids]]
|
||||
elsif not ids.first.is_a?(Array) # if single comp key passed, turn into an array of 1
|
||||
ids = [ids.to_composite_ids]
|
||||
end
|
||||
|
||||
where_clause = ids.map do |id_set|
|
||||
transposed = id_set.size == 1 ? [[full_keys, id_set.first]] : [full_keys, id_set].transpose
|
||||
transposed.map do |full_key, id|
|
||||
"#{full_key.to_s}=#{@reflection.klass.sanitize(id)}"
|
||||
end.join(" AND ")
|
||||
end.join(") OR (")
|
||||
|
||||
"(#{where_clause})"
|
||||
end
|
||||
|
||||
def composite_join_clause(full_keys1, full_keys2)
|
||||
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
|
||||
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
|
||||
|
||||
where_clause = [full_keys1, full_keys2].transpose.map do |key1, key2|
|
||||
"#{key1}=#{key2}"
|
||||
end.join(" AND ")
|
||||
|
||||
"(#{where_clause})"
|
||||
end
|
||||
|
||||
def full_composite_join_clause(table1, full_keys1, table2, full_keys2)
|
||||
connection = @reflection.active_record.connection
|
||||
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
|
||||
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
|
||||
|
||||
quoted1 = connection.quote_table_name(table1)
|
||||
quoted2 = connection.quote_table_name(table2)
|
||||
|
||||
where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
|
||||
"#{quoted1}.#{connection.quote_column_name(key_pair.first)}=#{quoted2}.#{connection.quote_column_name(key_pair.last)}"
|
||||
end.join(" AND ")
|
||||
|
||||
"(#{where_clause})"
|
||||
end
|
||||
|
||||
def full_keys(table_name, keys)
|
||||
connection = @reflection.active_record.connection
|
||||
quoted_table_name = connection.quote_table_name(table_name)
|
||||
keys = keys.split(CompositePrimaryKeys::ID_SEP) if keys.is_a?(String)
|
||||
if keys.is_a?(Array)
|
||||
keys.collect {|key| "#{quoted_table_name}.#{connection.quote_column_name(key)}"}.join(CompositePrimaryKeys::ID_SEP)
|
||||
else
|
||||
"#{quoted_table_name}.#{connection.quote_column_name(keys)}"
|
||||
end
|
||||
end
|
||||
|
||||
def full_columns_equals(table_name, keys, quoted_ids)
|
||||
connection = @reflection.active_record.connection
|
||||
quoted_table_name = connection.quote_table_name(table_name)
|
||||
if keys.is_a?(Symbol) or (keys.is_a?(String) and keys == keys.to_s.split(CompositePrimaryKeys::ID_SEP))
|
||||
return "#{quoted_table_name}.#{connection.quote_column_name(keys)} = #{quoted_ids}"
|
||||
end
|
||||
keys = keys.split(CompositePrimaryKeys::ID_SEP) if keys.is_a?(String)
|
||||
quoted_ids = quoted_ids.split(CompositePrimaryKeys::ID_SEP) if quoted_ids.is_a?(String)
|
||||
keys_ids = [keys, quoted_ids].transpose
|
||||
keys_ids.collect {|key, id| "(#{quoted_table_name}.#{connection.quote_column_name(key)} = #{id})"}.join(' AND ')
|
||||
end
|
||||
|
||||
def set_belongs_to_association_for(record)
|
||||
if @reflection.options[:as]
|
||||
record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
|
||||
record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
|
||||
else
|
||||
key_values = @reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP).zip([@owner.id].flatten)
|
||||
key_values.each{|key, value| record[key] = value} unless @owner.new_record?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
|
||||
def construct_sql
|
||||
@reflection.options[:finder_sql] &&= interpolate_sql(@reflection.options[:finder_sql])
|
||||
|
||||
if @reflection.options[:finder_sql]
|
||||
@finder_sql = @reflection.options[:finder_sql]
|
||||
else
|
||||
@finder_sql = full_columns_equals(@reflection.options[:join_table], @reflection.primary_key_name, @owner.quoted_id)
|
||||
@finder_sql << " AND (#{conditions})" if conditions
|
||||
end
|
||||
|
||||
@join_sql = "INNER JOIN #{@reflection.active_record.connection.quote_table_name(@reflection.options[:join_table])} ON " +
|
||||
full_composite_join_clause(@reflection.klass.table_name, @reflection.klass.primary_key, @reflection.options[:join_table], @reflection.association_foreign_key)
|
||||
end
|
||||
end
|
||||
|
||||
class HasManyAssociation < AssociationCollection #:nodoc:
|
||||
def construct_sql
|
||||
case
|
||||
when @reflection.options[:finder_sql]
|
||||
@finder_sql = interpolate_sql(@reflection.options[:finder_sql])
|
||||
|
||||
when @reflection.options[:as]
|
||||
@finder_sql =
|
||||
"#{@reflection.klass.quoted_table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
|
||||
"#{@reflection.klass.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
|
||||
@finder_sql << " AND (#{conditions})" if conditions
|
||||
|
||||
else
|
||||
@finder_sql = full_columns_equals(@reflection.klass.table_name, @reflection.primary_key_name, @owner.quoted_id)
|
||||
@finder_sql << " AND (#{conditions})" if conditions
|
||||
end
|
||||
|
||||
if @reflection.options[:counter_sql]
|
||||
@counter_sql = interpolate_sql(@reflection.options[:counter_sql])
|
||||
elsif @reflection.options[:finder_sql]
|
||||
# replace the SELECT clause with COUNT(*), preserving any hints within /* ... */
|
||||
@reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" }
|
||||
@counter_sql = interpolate_sql(@reflection.options[:counter_sql])
|
||||
else
|
||||
@counter_sql = @finder_sql
|
||||
end
|
||||
end
|
||||
|
||||
def delete_records(records)
|
||||
if @reflection.options[:dependent]
|
||||
records.each { |r| r.destroy }
|
||||
else
|
||||
connection = @reflection.active_record.connection
|
||||
field_names = @reflection.primary_key_name.split(',')
|
||||
field_names.collect! {|n| connection.quote_column_name(n) + " = NULL"}
|
||||
records.each do |r|
|
||||
where_clause = nil
|
||||
|
||||
if r.quoted_id.to_s.include?(CompositePrimaryKeys::ID_SEP)
|
||||
where_clause_terms = [@reflection.klass.primary_key, r.quoted_id].transpose.map do |pair|
|
||||
"(#{connection.quote_column_name(pair[0])} = #{pair[1]})"
|
||||
end
|
||||
where_clause = where_clause_terms.join(" AND ")
|
||||
else
|
||||
where_clause = connection.quote_column_name(@reflection.klass.primary_key) + ' = ' + r.quoted_id
|
||||
end
|
||||
|
||||
@reflection.klass.update_all( field_names.join(',') , where_clause)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class HasOneAssociation < BelongsToAssociation #:nodoc:
|
||||
def construct_sql
|
||||
case
|
||||
when @reflection.options[:as]
|
||||
@finder_sql =
|
||||
"#{@reflection.klass.quoted_table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
|
||||
"#{@reflection.klass.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
|
||||
else
|
||||
@finder_sql = full_columns_equals(@reflection.klass.table_name, @reflection.primary_key_name, @owner.quoted_id)
|
||||
end
|
||||
|
||||
@finder_sql << " AND (#{conditions})" if conditions
|
||||
end
|
||||
end
|
||||
|
||||
class HasManyThroughAssociation < HasManyAssociation #:nodoc:
|
||||
def construct_conditions_with_composite_keys
|
||||
if @reflection.through_reflection.options[:as]
|
||||
construct_conditions_without_composite_keys
|
||||
else
|
||||
conditions = full_columns_equals(@reflection.through_reflection.table_name, @reflection.through_reflection.primary_key_name, @owner.quoted_id)
|
||||
conditions << " AND (#{sql_conditions})" if sql_conditions
|
||||
conditions
|
||||
end
|
||||
end
|
||||
alias_method_chain :construct_conditions, :composite_keys
|
||||
|
||||
def construct_joins_with_composite_keys(custom_joins = nil)
|
||||
if @reflection.through_reflection.options[:as] || @reflection.source_reflection.options[:as]
|
||||
construct_joins_without_composite_keys(custom_joins)
|
||||
else
|
||||
if @reflection.source_reflection.macro == :belongs_to
|
||||
reflection_primary_key = @reflection.klass.primary_key
|
||||
source_primary_key = @reflection.source_reflection.primary_key_name
|
||||
else
|
||||
reflection_primary_key = @reflection.source_reflection.primary_key_name
|
||||
source_primary_key = @reflection.klass.primary_key
|
||||
end
|
||||
|
||||
"INNER JOIN %s ON %s #{@reflection.options[:joins]} #{custom_joins}" % [
|
||||
@reflection.through_reflection.quoted_table_name,
|
||||
composite_join_clause(full_keys(@reflection.table_name, reflection_primary_key), full_keys(@reflection.through_reflection.table_name, source_primary_key))
|
||||
]
|
||||
end
|
||||
end
|
||||
alias_method_chain :construct_joins, :composite_keys
|
||||
end
|
||||
end
|
|
@ -1,84 +0,0 @@
|
|||
module CompositePrimaryKeys
|
||||
module ActiveRecord
|
||||
module AttributeMethods #:nodoc:
|
||||
def self.append_features(base)
|
||||
super
|
||||
base.send(:extend, ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Define an attribute reader method. Cope with nil column.
|
||||
def define_read_method(symbol, attr_name, column)
|
||||
cast_code = column.type_cast_code('v') if column
|
||||
cast_code = "::#{cast_code}" if cast_code && cast_code.match('ActiveRecord::.*')
|
||||
access_code = cast_code ? "(v=@attributes['#{attr_name}']) && #{cast_code}" : "@attributes['#{attr_name}']"
|
||||
|
||||
unless self.primary_keys.include?(attr_name.to_sym)
|
||||
access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
|
||||
end
|
||||
|
||||
if cache_attribute?(attr_name)
|
||||
access_code = "@attributes_cache['#{attr_name}'] ||= (#{access_code})"
|
||||
end
|
||||
|
||||
evaluate_attribute_method attr_name, "def #{symbol}; #{access_code}; end"
|
||||
end
|
||||
|
||||
# Evaluate the definition for an attribute related method
|
||||
def evaluate_attribute_method(attr_name, method_definition, method_name=attr_name)
|
||||
unless primary_keys.include?(method_name.to_sym)
|
||||
generated_methods << method_name
|
||||
end
|
||||
|
||||
begin
|
||||
class_eval(method_definition, __FILE__, __LINE__)
|
||||
rescue SyntaxError => err
|
||||
generated_methods.delete(attr_name)
|
||||
if logger
|
||||
logger.warn "Exception occurred during reader method compilation."
|
||||
logger.warn "Maybe #{attr_name} is not a valid Ruby identifier?"
|
||||
logger.warn "#{err.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Allows access to the object attributes, which are held in the @attributes hash, as though they
|
||||
# were first-class methods. So a Person class with a name attribute can use Person#name and
|
||||
# Person#name= and never directly use the attributes hash -- except for multiple assigns with
|
||||
# ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that
|
||||
# the completed attribute is not nil or 0.
|
||||
#
|
||||
# It's also possible to instantiate related objects, so a Client class belonging to the clients
|
||||
# table with a master_id foreign key can instantiate master through Client#master.
|
||||
def method_missing(method_id, *args, &block)
|
||||
method_name = method_id.to_s
|
||||
|
||||
# If we haven't generated any methods yet, generate them, then
|
||||
# see if we've created the method we're looking for.
|
||||
if !self.class.generated_methods?
|
||||
self.class.define_attribute_methods
|
||||
|
||||
if self.class.generated_methods.include?(method_name)
|
||||
return self.send(method_id, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
if self.class.primary_keys.include?(method_name.to_sym)
|
||||
ids[self.class.primary_keys.index(method_name.to_sym)]
|
||||
elsif md = self.class.match_attribute_method?(method_name)
|
||||
attribute_name, method_type = md.pre_match, md.to_s
|
||||
if @attributes.include?(attribute_name)
|
||||
__send__("attribute#{method_type}", attribute_name, *args, &block)
|
||||
else
|
||||
super
|
||||
end
|
||||
elsif @attributes.include?(method_name)
|
||||
read_attribute(method_name)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,337 +0,0 @@
|
|||
module CompositePrimaryKeys
|
||||
module ActiveRecord #:nodoc:
|
||||
class CompositeKeyError < StandardError #:nodoc:
|
||||
end
|
||||
|
||||
module Base #:nodoc:
|
||||
|
||||
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
||||
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
||||
|
||||
def self.append_features(base)
|
||||
super
|
||||
base.send(:include, InstanceMethods)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def set_primary_keys(*keys)
|
||||
keys = keys.first if keys.first.is_a?(Array)
|
||||
keys = keys.map { |k| k.to_sym }
|
||||
cattr_accessor :primary_keys
|
||||
self.primary_keys = keys.to_composite_keys
|
||||
|
||||
class_eval <<-EOV
|
||||
extend CompositeClassMethods
|
||||
include CompositeInstanceMethods
|
||||
|
||||
include CompositePrimaryKeys::ActiveRecord::Associations
|
||||
include CompositePrimaryKeys::ActiveRecord::AssociationPreload
|
||||
include CompositePrimaryKeys::ActiveRecord::Calculations
|
||||
include CompositePrimaryKeys::ActiveRecord::AttributeMethods
|
||||
EOV
|
||||
end
|
||||
|
||||
def composite?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def composite?; self.class.composite?; end
|
||||
end
|
||||
|
||||
module CompositeInstanceMethods
|
||||
|
||||
# A model instance's primary keys is always available as model.ids
|
||||
# whether you name it the default 'id' or set it to something else.
|
||||
def id
|
||||
attr_names = self.class.primary_keys
|
||||
CompositeIds.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
||||
end
|
||||
alias_method :ids, :id
|
||||
|
||||
def to_param
|
||||
id.to_s
|
||||
end
|
||||
|
||||
def id_before_type_cast #:nodoc:
|
||||
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::NOT_IMPLEMENTED_YET
|
||||
end
|
||||
|
||||
def quoted_id #:nodoc:
|
||||
[self.class.primary_keys, ids].
|
||||
transpose.
|
||||
map {|attr_name,id| quote_value(id, column_for_attribute(attr_name))}.
|
||||
to_composite_ids
|
||||
end
|
||||
|
||||
# Sets the primary ID.
|
||||
def id=(ids)
|
||||
ids = ids.split(ID_SEP) if ids.is_a?(String)
|
||||
ids.flatten!
|
||||
unless ids.is_a?(Array) and ids.length == self.class.primary_keys.length
|
||||
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
|
||||
end
|
||||
[primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
||||
id
|
||||
end
|
||||
|
||||
# Returns a clone of the record that hasn't been assigned an id yet and
|
||||
# is treated as a new record. Note that this is a "shallow" clone:
|
||||
# it copies the object's attributes only, not its associations.
|
||||
# The extent of a "deep" clone is application-specific and is therefore
|
||||
# left to the application to implement according to its need.
|
||||
def clone
|
||||
attrs = self.attributes_before_type_cast
|
||||
self.class.primary_keys.each {|key| attrs.delete(key.to_s)}
|
||||
self.class.new do |record|
|
||||
record.send :instance_variable_set, '@attributes', attrs
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
# The xx_without_callbacks methods are overwritten as that is the end of the alias chain
|
||||
|
||||
# Creates a new record with values matching those of the instance attributes.
|
||||
def create_without_callbacks
|
||||
unless self.id
|
||||
raise CompositeKeyError, "Composite keys do not generated ids from sequences, you must provide id values"
|
||||
end
|
||||
attributes_minus_pks = attributes_with_quotes(false)
|
||||
quoted_pk_columns = self.class.primary_key.map { |col| connection.quote_column_name(col) }
|
||||
cols = quoted_column_names(attributes_minus_pks) << quoted_pk_columns
|
||||
vals = attributes_minus_pks.values << quoted_id
|
||||
connection.insert(
|
||||
"INSERT INTO #{self.class.quoted_table_name} " +
|
||||
"(#{cols.join(', ')}) " +
|
||||
"VALUES (#{vals.join(', ')})",
|
||||
"#{self.class.name} Create",
|
||||
self.class.primary_key,
|
||||
self.id
|
||||
)
|
||||
@new_record = false
|
||||
return true
|
||||
end
|
||||
|
||||
# Updates the associated record with values matching those of the instance attributes.
|
||||
def update_without_callbacks
|
||||
where_clause_terms = [self.class.primary_key, quoted_id].transpose.map do |pair|
|
||||
"(#{connection.quote_column_name(pair[0])} = #{pair[1]})"
|
||||
end
|
||||
where_clause = where_clause_terms.join(" AND ")
|
||||
connection.update(
|
||||
"UPDATE #{self.class.quoted_table_name} " +
|
||||
"SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " +
|
||||
"WHERE #{where_clause}",
|
||||
"#{self.class.name} Update"
|
||||
)
|
||||
return true
|
||||
end
|
||||
|
||||
# Deletes the record in the database and freezes this instance to reflect that no changes should
|
||||
# be made (since they can't be persisted).
|
||||
def destroy_without_callbacks
|
||||
where_clause_terms = [self.class.primary_key, quoted_id].transpose.map do |pair|
|
||||
"(#{connection.quote_column_name(pair[0])} = #{pair[1]})"
|
||||
end
|
||||
where_clause = where_clause_terms.join(" AND ")
|
||||
unless new_record?
|
||||
connection.delete(
|
||||
"DELETE FROM #{self.class.quoted_table_name} " +
|
||||
"WHERE #{where_clause}",
|
||||
"#{self.class.name} Destroy"
|
||||
)
|
||||
end
|
||||
freeze
|
||||
end
|
||||
end
|
||||
|
||||
module CompositeClassMethods
|
||||
def primary_key; primary_keys; end
|
||||
def primary_key=(keys); primary_keys = keys; end
|
||||
|
||||
def composite?
|
||||
true
|
||||
end
|
||||
|
||||
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
||||
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
||||
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
||||
many_ids.map {|ids| "#{left_bracket}#{ids}#{right_bracket}"}.join(list_sep)
|
||||
end
|
||||
|
||||
# Creates WHERE condition from list of composited ids
|
||||
# User.update_all({:role => 'admin'}, :conditions => composite_where_clause([[1, 2], [2, 2]])) #=> UPDATE admins SET admin.role='admin' WHERE (admin.type=1 AND admin.type2=2) OR (admin.type=2 AND admin.type2=2)
|
||||
# User.find(:all, :conditions => composite_where_clause([[1, 2], [2, 2]])) #=> SELECT * FROM admins WHERE (admin.type=1 AND admin.type2=2) OR (admin.type=2 AND admin.type2=2)
|
||||
def composite_where_clause(ids)
|
||||
if ids.is_a?(String)
|
||||
ids = [[ids]]
|
||||
elsif not ids.first.is_a?(Array) # if single comp key passed, turn into an array of 1
|
||||
ids = [ids.to_composite_ids]
|
||||
end
|
||||
|
||||
ids.map do |id_set|
|
||||
[primary_keys, id_set].transpose.map do |key, id|
|
||||
"#{table_name}.#{key.to_s}=#{sanitize(id)}"
|
||||
end.join(" AND ")
|
||||
end.join(") OR (")
|
||||
end
|
||||
|
||||
# Returns true if the given +ids+ represents the primary keys of a record in the database, false otherwise.
|
||||
# Example:
|
||||
# Person.exists?(5,7)
|
||||
def exists?(ids)
|
||||
obj = find(ids) rescue false
|
||||
!obj.nil? and obj.is_a?(self)
|
||||
end
|
||||
|
||||
# Deletes the record with the given +ids+ without instantiating an object first, e.g. delete(1,2)
|
||||
# If an array of ids is provided (e.g. delete([1,2], [3,4]), all of them
|
||||
# are deleted.
|
||||
def delete(*ids)
|
||||
unless ids.is_a?(Array); raise "*ids must be an Array"; end
|
||||
ids = [ids.to_composite_ids] if not ids.first.is_a?(Array)
|
||||
where_clause = ids.map do |id_set|
|
||||
[primary_keys, id_set].transpose.map do |key, id|
|
||||
"#{quoted_table_name}.#{connection.quote_column_name(key.to_s)}=#{sanitize(id)}"
|
||||
end.join(" AND ")
|
||||
end.join(") OR (")
|
||||
delete_all([ "(#{where_clause})" ])
|
||||
end
|
||||
|
||||
# Destroys the record with the given +ids+ by instantiating the object and calling #destroy (all the callbacks are the triggered).
|
||||
# If an array of ids is provided, all of them are destroyed.
|
||||
def destroy(*ids)
|
||||
unless ids.is_a?(Array); raise "*ids must be an Array"; end
|
||||
if ids.first.is_a?(Array)
|
||||
ids = ids.map{|compids| compids.to_composite_ids}
|
||||
else
|
||||
ids = ids.to_composite_ids
|
||||
end
|
||||
ids.first.is_a?(CompositeIds) ? ids.each { |id_set| find(id_set).destroy } : find(ids).destroy
|
||||
end
|
||||
|
||||
# Returns an array of column objects for the table associated with this class.
|
||||
# Each column that matches to one of the primary keys has its
|
||||
# primary attribute set to true
|
||||
def columns
|
||||
unless @columns
|
||||
@columns = connection.columns(table_name, "#{name} Columns")
|
||||
@columns.each {|column| column.primary = primary_keys.include?(column.name.to_sym)}
|
||||
end
|
||||
@columns
|
||||
end
|
||||
|
||||
## DEACTIVATED METHODS ##
|
||||
public
|
||||
# Lazy-set the sequence name to the connection's default. This method
|
||||
# is only ever called once since set_sequence_name overrides it.
|
||||
def sequence_name #:nodoc:
|
||||
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
|
||||
end
|
||||
|
||||
def reset_sequence_name #:nodoc:
|
||||
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
|
||||
end
|
||||
|
||||
def set_primary_key(value = nil, &block)
|
||||
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
|
||||
end
|
||||
|
||||
private
|
||||
def find_one(id, options)
|
||||
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
|
||||
end
|
||||
|
||||
def find_some(ids, options)
|
||||
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
|
||||
end
|
||||
|
||||
def find_from_ids(ids, options)
|
||||
ids = ids.first if ids.last == nil
|
||||
conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
|
||||
# if ids is just a flat list, then its size must = primary_key.length (one id per primary key, in order)
|
||||
# if ids is list of lists, then each inner list must follow rule above
|
||||
if ids.first.is_a? String
|
||||
# find '2,1' -> ids = ['2,1']
|
||||
# find '2,1;7,3' -> ids = ['2,1;7,3']
|
||||
ids = ids.first.split(ID_SET_SEP).map {|id_set| id_set.split(ID_SEP).to_composite_ids}
|
||||
# find '2,1;7,3' -> ids = [['2','1'],['7','3']], inner [] are CompositeIds
|
||||
end
|
||||
ids = [ids.to_composite_ids] if not ids.first.kind_of?(Array)
|
||||
ids.each do |id_set|
|
||||
unless id_set.is_a?(Array)
|
||||
raise "Ids must be in an Array, instead received: #{id_set.inspect}"
|
||||
end
|
||||
unless id_set.length == primary_keys.length
|
||||
raise "#{id_set.inspect}: Incorrect number of primary keys for #{class_name}: #{primary_keys.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
# Let keys = [:a, :b]
|
||||
# If ids = [[10, 50], [11, 51]], then :conditions =>
|
||||
# "(#{quoted_table_name}.a, #{quoted_table_name}.b) IN ((10, 50), (11, 51))"
|
||||
|
||||
conditions = ids.map do |id_set|
|
||||
[primary_keys, id_set].transpose.map do |key, id|
|
||||
col = columns_hash[key.to_s]
|
||||
val = quote_value(id, col)
|
||||
"#{quoted_table_name}.#{connection.quote_column_name(key.to_s)}=#{val}"
|
||||
end.join(" AND ")
|
||||
end.join(") OR (")
|
||||
|
||||
options.update :conditions => "(#{conditions})"
|
||||
|
||||
result = find_every(options)
|
||||
|
||||
if result.size == ids.size
|
||||
ids.size == 1 ? result[0] : result
|
||||
else
|
||||
raise ::ActiveRecord::RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids.inspect})#{conditions}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module ActiveRecord
|
||||
ID_SEP = ','
|
||||
ID_SET_SEP = ';'
|
||||
|
||||
class Base
|
||||
# Allows +attr_name+ to be the list of primary_keys, and returns the id
|
||||
# of the object
|
||||
# e.g. @object[@object.class.primary_key] => [1,1]
|
||||
def [](attr_name)
|
||||
if attr_name.is_a?(String) and attr_name != attr_name.split(ID_SEP).first
|
||||
attr_name = attr_name.split(ID_SEP)
|
||||
end
|
||||
attr_name.is_a?(Array) ?
|
||||
attr_name.map {|name| read_attribute(name)} :
|
||||
read_attribute(attr_name)
|
||||
end
|
||||
|
||||
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
|
||||
# (Alias for the protected write_attribute method).
|
||||
def []=(attr_name, value)
|
||||
if attr_name.is_a?(String) and attr_name != attr_name.split(ID_SEP).first
|
||||
attr_name = attr_name.split(ID_SEP)
|
||||
end
|
||||
|
||||
if attr_name.is_a? Array
|
||||
value = value.split(ID_SEP) if value.is_a? String
|
||||
unless value.length == attr_name.length
|
||||
raise "Number of attr_names and values do not match"
|
||||
end
|
||||
#breakpoint
|
||||
[attr_name, value].transpose.map {|name,val| write_attribute(name.to_s, val)}
|
||||
else
|
||||
write_attribute(attr_name, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,68 +0,0 @@
|
|||
module CompositePrimaryKeys
|
||||
module ActiveRecord
|
||||
module Calculations
|
||||
def self.append_features(base)
|
||||
super
|
||||
base.send(:extend, ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def construct_calculation_sql(operation, column_name, options) #:nodoc:
|
||||
operation = operation.to_s.downcase
|
||||
options = options.symbolize_keys
|
||||
|
||||
scope = scope(:find)
|
||||
merged_includes = merge_includes(scope ? scope[:include] : [], options[:include])
|
||||
aggregate_alias = column_alias_for(operation, column_name)
|
||||
use_workaround = !connection.supports_count_distinct? && options[:distinct] && operation.to_s.downcase == 'count'
|
||||
join_dependency = nil
|
||||
|
||||
if merged_includes.any? && operation.to_s.downcase == 'count'
|
||||
options[:distinct] = true
|
||||
use_workaround = !connection.supports_count_distinct?
|
||||
column_name = options[:select] || primary_key.map{ |part| "#{quoted_table_name}.#{connection.quote_column_name(part)}"}.join(',')
|
||||
end
|
||||
|
||||
sql = "SELECT #{operation}(#{'DISTINCT ' if options[:distinct]}#{column_name}) AS #{aggregate_alias}"
|
||||
|
||||
# A (slower) workaround if we're using a backend, like sqlite, that doesn't support COUNT DISTINCT.
|
||||
sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
|
||||
|
||||
sql << ", #{connection.quote_column_name(options[:group_field])} AS #{options[:group_alias]}" if options[:group]
|
||||
sql << " FROM (SELECT DISTINCT #{column_name}" if use_workaround
|
||||
sql << " FROM #{quoted_table_name} "
|
||||
if merged_includes.any?
|
||||
join_dependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
|
||||
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
|
||||
end
|
||||
add_joins!(sql, options, scope)
|
||||
add_conditions!(sql, options[:conditions], scope)
|
||||
add_limited_ids_condition!(sql, options, join_dependency) if \
|
||||
join_dependency &&
|
||||
!using_limitable_reflections?(join_dependency.reflections) &&
|
||||
((scope && scope[:limit]) || options[:limit])
|
||||
|
||||
if options[:group]
|
||||
group_key = connection.adapter_name == 'FrontBase' ? :group_alias : :group_field
|
||||
sql << " GROUP BY #{connection.quote_column_name(options[group_key])} "
|
||||
end
|
||||
|
||||
if options[:group] && options[:having]
|
||||
# FrontBase requires identifiers in the HAVING clause and chokes on function calls
|
||||
if connection.adapter_name == 'FrontBase'
|
||||
options[:having].downcase!
|
||||
options[:having].gsub!(/#{operation}\s*\(\s*#{column_name}\s*\)/, aggregate_alias)
|
||||
end
|
||||
|
||||
sql << " HAVING #{options[:having]} "
|
||||
end
|
||||
|
||||
sql << " ORDER BY #{options[:order]} " if options[:order]
|
||||
add_limit!(sql, options, scope)
|
||||
sql << ') w1' if use_workaround # assign a dummy table name as required for postgresql
|
||||
sql
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
module CompositePrimaryKeys
|
||||
ID_SEP = ','
|
||||
ID_SET_SEP = ';'
|
||||
|
||||
module ArrayExtension
|
||||
def to_composite_keys
|
||||
CompositeKeys.new(self)
|
||||
end
|
||||
|
||||
def to_composite_ids
|
||||
CompositeIds.new(self)
|
||||
end
|
||||
end
|
||||
|
||||
class CompositeArray < Array
|
||||
def to_s
|
||||
join(ID_SEP)
|
||||
end
|
||||
end
|
||||
|
||||
class CompositeKeys < CompositeArray
|
||||
|
||||
end
|
||||
|
||||
class CompositeIds < CompositeArray
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Array.send(:include, CompositePrimaryKeys::ArrayExtension)
|
|
@ -1,21 +0,0 @@
|
|||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class IBM_DBAdapter < AbstractAdapter
|
||||
|
||||
# This mightn't be in Core, but count(distinct x,y) doesn't work for me
|
||||
def supports_count_distinct? #:nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
alias_method :quote_original, :quote
|
||||
def quote(value, column = nil)
|
||||
if value.kind_of?(String) && column && [:integer, :float].include?(column.type)
|
||||
value = column.type == :integer ? value.to_i : value.to_f
|
||||
value.to_s
|
||||
else
|
||||
quote_original(value, column)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class OracleAdapter < AbstractAdapter
|
||||
|
||||
# This mightn't be in Core, but count(distinct x,y) doesn't work for me
|
||||
def supports_count_distinct? #:nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
def concat(*columns)
|
||||
"(#{columns.join('||')})"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,53 +0,0 @@
|
|||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class PostgreSQLAdapter < AbstractAdapter
|
||||
|
||||
# This mightn't be in Core, but count(distinct x,y) doesn't work for me
|
||||
def supports_count_distinct? #:nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
def concat(*columns)
|
||||
columns = columns.map { |c| "CAST(#{c} AS varchar)" }
|
||||
"(#{columns.join('||')})"
|
||||
end
|
||||
|
||||
# Executes an INSERT query and returns the new record's ID
|
||||
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
||||
# Extract the table from the insert sql. Yuck.
|
||||
table = sql.split(" ", 4)[2].gsub('"', '')
|
||||
|
||||
# Try an insert with 'returning id' if available (PG >= 8.2)
|
||||
if supports_insert_with_returning?
|
||||
pk, sequence_name = *pk_and_sequence_for(table) unless pk
|
||||
if pk
|
||||
quoted_pk = if pk.is_a?(Array)
|
||||
pk.map { |col| quote_column_name(col) }.join(ID_SEP)
|
||||
else
|
||||
quote_column_name(pk)
|
||||
end
|
||||
id = select_value("#{sql} RETURNING #{quoted_pk}")
|
||||
clear_query_cache
|
||||
return id
|
||||
end
|
||||
end
|
||||
|
||||
# Otherwise, insert then grab last_insert_id.
|
||||
if insert_id = super
|
||||
insert_id
|
||||
else
|
||||
# If neither pk nor sequence name is given, look them up.
|
||||
unless pk || sequence_name
|
||||
pk, sequence_name = *pk_and_sequence_for(table)
|
||||
end
|
||||
|
||||
# If a pk is given, fallback to default sequence name.
|
||||
# Don't fetch last insert id for a table without a pk.
|
||||
if pk && sequence_name ||= default_sequence_name(table, pk)
|
||||
last_insert_id(table, sequence_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
require 'active_record/connection_adapters/sqlite_adapter'
|
||||
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters #:nodoc:
|
||||
class SQLite3Adapter < SQLiteAdapter # :nodoc:
|
||||
def supports_count_distinct? #:nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
def concat(*columns)
|
||||
"(#{columns.join('||')})"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +0,0 @@
|
|||
class Fixture #:nodoc:
|
||||
def [](key)
|
||||
if key.is_a? Array
|
||||
return key.map { |a_key| self[a_key.to_s] }.to_composite_ids.to_s
|
||||
end
|
||||
@fixture[key]
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
ActiveRecord::ConnectionAdapters::ColumnDefinition.send(:alias_method, :to_s_without_composite_keys, :to_s)
|
||||
|
||||
ActiveRecord::ConnectionAdapters::ColumnDefinition.class_eval <<-'EOF'
|
||||
def to_s
|
||||
if name.is_a? Array
|
||||
"PRIMARY KEY (#{name.join(',')})"
|
||||
else
|
||||
to_s_without_composite_keys
|
||||
end
|
||||
end
|
||||
EOF
|
||||
|
||||
ActiveRecord::ConnectionAdapters::TableDefinition.class_eval <<-'EOF'
|
||||
def [](name)
|
||||
@columns.find { |column|
|
||||
!column.name.is_a?(Array) && column.name.to_s == name.to_s
|
||||
}
|
||||
end
|
||||
EOF
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
module ActiveRecord
|
||||
module Reflection
|
||||
class AssociationReflection
|
||||
def primary_key_name
|
||||
return @primary_key_name if @primary_key_name
|
||||
case
|
||||
when macro == :belongs_to
|
||||
@primary_key_name = options[:foreign_key] || class_name.foreign_key
|
||||
when options[:as]
|
||||
@primary_key_name = options[:foreign_key] || "#{options[:as]}_id"
|
||||
else
|
||||
@primary_key_name = options[:foreign_key] || active_record.name.foreign_key
|
||||
end
|
||||
@primary_key_name = @primary_key_name.to_composite_keys.to_s if @primary_key_name.is_a? Array
|
||||
@primary_key_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +0,0 @@
|
|||
module CompositePrimaryKeys
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 1
|
||||
MINOR = 1
|
||||
TINY = 0
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
# Load local config files in /local
|
||||
begin
|
||||
local_file_supported = Dir[File.join(PROJECT_ROOT, 'local/*.sample')].map { |path| File.basename(path).sub(".sample","") }
|
||||
local_file_supported.each do |file|
|
||||
require "local/#{file}"
|
||||
end
|
||||
rescue LoadError
|
||||
puts <<-EOS
|
||||
This Gem supports local developer extensions in local/ folder.
|
||||
Supported files:
|
||||
#{local_file_supported.map { |f| "local/#{f}"}.join(', ')}
|
||||
|
||||
Setup default sample files:
|
||||
rake local:setup
|
||||
|
||||
Current warning: #{$!}
|
||||
|
||||
EOS
|
||||
end
|
||||
|
||||
|
||||
# Now load Rake tasks from /tasks
|
||||
rakefiles = Dir[File.join(File.dirname(__FILE__), "tasks/**/*.rake")]
|
||||
rakefiles.each { |rakefile| load File.expand_path(rakefile) }
|
|
@ -1,10 +0,0 @@
|
|||
require 'yaml'
|
||||
|
||||
ENV['cpk_adapters'] = {
|
||||
"mysql" => {
|
||||
:adapter => "mysql",
|
||||
:username => "root",
|
||||
:password => "root",
|
||||
# ...
|
||||
}
|
||||
}.to_yaml
|
|
@ -1,2 +0,0 @@
|
|||
# location of folder containing activerecord, railties, etc folders for each Rails gem
|
||||
ENV['EDGE_RAILS_DIR'] ||= "/path/to/copy/of/edge/rails"
|
|
@ -1,2 +0,0 @@
|
|||
# This file loaded into Rakefile
|
||||
# Place any extra development tasks you want here
|
|
@ -1,48 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
#
|
||||
# if run as script, load the file as library while starting irb
|
||||
#
|
||||
if __FILE__ == $0
|
||||
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
||||
ENV['ADAPTER'] = ARGV[0]
|
||||
exec "#{irb} -f -r #{$0} --simple-prompt"
|
||||
end
|
||||
|
||||
#
|
||||
# check if the given adapter is supported (default: mysql)
|
||||
#
|
||||
adapters = %w[mysql sqlite oracle oracle_enhanced postgresql ibm_db]
|
||||
adapter = ENV['ADAPTER'] || 'mysql'
|
||||
unless adapters.include? adapter
|
||||
puts "Usage: #{__FILE__} <adapter>"
|
||||
puts ''
|
||||
puts 'Adapters: '
|
||||
puts adapters.map{ |adapter| " #{adapter}" }.join("\n")
|
||||
exit 1
|
||||
end
|
||||
|
||||
#
|
||||
# load all necessary libraries
|
||||
#
|
||||
require 'rubygems'
|
||||
require 'local/database_connections'
|
||||
|
||||
$LOAD_PATH.unshift 'lib'
|
||||
|
||||
begin
|
||||
require 'local/paths'
|
||||
$LOAD_PATH.unshift "#{ENV['EDGE_RAILS_DIR']}/activerecord/lib" if ENV['EDGE_RAILS_DIR']
|
||||
$LOAD_PATH.unshift "#{ENV['EDGE_RAILS_DIR']}/activesupport/lib" if ENV['EDGE_RAILS_DIR']
|
||||
rescue
|
||||
end
|
||||
|
||||
require 'active_support'
|
||||
require 'active_record'
|
||||
|
||||
require "test/connections/native_#{adapter}/connection"
|
||||
require 'composite_primary_keys'
|
||||
|
||||
PROJECT_ROOT = File.join(File.dirname(__FILE__), '..')
|
||||
Dir[File.join(PROJECT_ROOT,'test/fixtures/*.rb')].each { |model| require model }
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rubygems'
|
||||
require 'redcloth'
|
||||
require 'syntax/convertors/html'
|
||||
require 'erb'
|
||||
require File.dirname(__FILE__) + '/../lib/composite_primary_keys/version.rb'
|
||||
|
||||
version = CompositePrimaryKeys::VERSION::STRING
|
||||
download = 'http://rubyforge.org/projects/compositekeys'
|
||||
|
||||
class Fixnum
|
||||
def ordinal
|
||||
# teens
|
||||
return 'th' if (10..19).include?(self % 100)
|
||||
# others
|
||||
case self % 10
|
||||
when 1: return 'st'
|
||||
when 2: return 'nd'
|
||||
when 3: return 'rd'
|
||||
else return 'th'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Time
|
||||
def pretty
|
||||
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
||||
end
|
||||
end
|
||||
|
||||
def convert_syntax(syntax, source)
|
||||
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
||||
end
|
||||
|
||||
if ARGV.length >= 1
|
||||
src, template = ARGV
|
||||
template ||= File.dirname(__FILE__) + '/../website/template.rhtml'
|
||||
|
||||
else
|
||||
puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
|
||||
exit!
|
||||
end
|
||||
|
||||
template = ERB.new(File.open(template).read)
|
||||
|
||||
title = nil
|
||||
body = nil
|
||||
File.open(src) do |fsrc|
|
||||
title_text = fsrc.readline
|
||||
body_text = fsrc.read
|
||||
syntax_items = []
|
||||
body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
|
||||
ident = syntax_items.length
|
||||
element, syntax, source = $1, $2, $3
|
||||
syntax_items << "<#{element} class=\"syntax\">#{convert_syntax(syntax, source)}</#{element}>"
|
||||
"syntax-temp-#{ident}"
|
||||
}
|
||||
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
||||
body = RedCloth.new(body_text).to_html
|
||||
body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
|
||||
end
|
||||
stat = File.stat(src)
|
||||
created = stat.ctime
|
||||
modified = stat.mtime
|
||||
|
||||
$stdout << template.result(binding)
|
|
@ -1,59 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rubygems'
|
||||
require 'redcloth'
|
||||
require 'syntax/convertors/html'
|
||||
require 'erb'
|
||||
require 'active_support'
|
||||
require File.dirname(__FILE__) + '/../lib/composite_primary_keys/version.rb'
|
||||
|
||||
version = CompositePrimaryKeys::VERSION::STRING
|
||||
download = 'http://rubyforge.org/projects/compositekeys'
|
||||
|
||||
class Fixnum
|
||||
def ordinal
|
||||
# teens
|
||||
return 'th' if (10..19).include?(self % 100)
|
||||
# others
|
||||
case self % 10
|
||||
when 1: return 'st'
|
||||
when 2: return 'nd'
|
||||
when 3: return 'rd'
|
||||
else return 'th'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Time
|
||||
def pretty
|
||||
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
||||
end
|
||||
end
|
||||
|
||||
def convert_syntax(syntax, source)
|
||||
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
||||
end
|
||||
|
||||
if ARGV.length >= 1
|
||||
src, template = ARGV
|
||||
template ||= File.dirname(__FILE__) + '/../website/template.js'
|
||||
else
|
||||
puts("Usage: #{File.split($0).last} source.txt [template.js] > output.html")
|
||||
exit!
|
||||
end
|
||||
|
||||
template = ERB.new(File.open(template).read)
|
||||
|
||||
title = nil
|
||||
body = nil
|
||||
File.open(src) do |fsrc|
|
||||
title_text = fsrc.readline
|
||||
body_text = fsrc.read
|
||||
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
||||
body = RedCloth.new(body_text)
|
||||
end
|
||||
stat = File.stat(src)
|
||||
created = stat.ctime
|
||||
modified = stat.mtime
|
||||
|
||||
$stdout << template.result(binding)
|
|
@ -1,43 +0,0 @@
|
|||
namespace :ar do
|
||||
desc 'Pre-load edge rails ActiveRecord'
|
||||
task :edge do
|
||||
unless path = ENV['EDGE_RAILS_DIR'] || ENV['EDGE_RAILS']
|
||||
puts <<-EOS
|
||||
|
||||
Need to define env var EDGE_RAILS_DIR or EDGE_RAILS- root of edge rails on your machine.
|
||||
i) Get copy of Edge Rails - http://dev.rubyonrails.org
|
||||
ii) Set EDGE_RAILS_DIR to this folder in local/paths.rb - see local/paths.rb.sample for example
|
||||
or
|
||||
a) Set folder from environment or command line (rake ar:edge EDGE_RAILS_DIR=/path/to/rails)
|
||||
|
||||
EOS
|
||||
exit
|
||||
end
|
||||
|
||||
ENV['AR_LOAD_PATH'] = File.join(path, "activerecord/lib")
|
||||
end
|
||||
|
||||
desc 'Pre-load ActiveRecord using VERSION=X.Y.Z, instead of latest'
|
||||
task :set do
|
||||
unless version = ENV['VERSION']
|
||||
puts <<-EOS
|
||||
Usage: rake ar:get_version VERSION=1.15.3
|
||||
Specify the version number with VERSION=X.Y.Z; and make sure you have that activerecord gem version installed.
|
||||
|
||||
EOS
|
||||
end
|
||||
version = nil if version == "" || version == []
|
||||
begin
|
||||
version ? gem('activerecord', version) : gem('activerecord')
|
||||
require 'active_record'
|
||||
ENV['AR_LOAD_PATH'] = $:.reverse.find { |path| /activerecord/ =~ path }
|
||||
rescue LoadError
|
||||
puts <<-EOS
|
||||
Missing: Cannot find activerecord #{version} installed.
|
||||
Install: gem install activerecord -v #{version}
|
||||
|
||||
EOS
|
||||
exit
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,12 +0,0 @@
|
|||
require 'active_record'
|
||||
|
||||
# UNTESTED - firebird sqlserver sqlserver_odbc db2 sybase openbase
|
||||
for adapter in %w( mysql sqlite oracle oracle_enhanced postgresql ibm_db )
|
||||
Rake::TestTask.new("test_#{adapter}") { |t|
|
||||
t.libs << "test" << "test/connections/native_#{adapter}"
|
||||
t.pattern = "test/test_*.rb"
|
||||
t.verbose = true
|
||||
}
|
||||
end
|
||||
|
||||
SCHEMA_PATH = File.join(PROJECT_ROOT, *%w(test fixtures db_definitions))
|
|
@ -1,30 +0,0 @@
|
|||
namespace :mysql do
|
||||
desc 'Build the MySQL test databases'
|
||||
task :build_databases => :load_connection do
|
||||
puts File.join(SCHEMA_PATH, 'mysql.sql')
|
||||
options_str = ENV['cpk_adapter_options_str']
|
||||
# creates something like "-u#{username} -p#{password} -S#{socket}"
|
||||
sh %{ mysqladmin #{options_str} create "#{GEM_NAME}_unittest" }
|
||||
sh %{ mysql #{options_str} "#{GEM_NAME}_unittest" < #{File.join(SCHEMA_PATH, 'mysql.sql')} }
|
||||
end
|
||||
|
||||
desc 'Drop the MySQL test databases'
|
||||
task :drop_databases => :load_connection do
|
||||
options_str = ENV['cpk_adapter_options_str']
|
||||
sh %{ mysqladmin #{options_str} -f drop "#{GEM_NAME}_unittest" }
|
||||
end
|
||||
|
||||
desc 'Rebuild the MySQL test databases'
|
||||
task :rebuild_databases => [:drop_databases, :build_databases]
|
||||
|
||||
task :load_connection do
|
||||
require File.join(PROJECT_ROOT, %w[lib adapter_helper mysql])
|
||||
spec = AdapterHelper::MySQL.load_connection_from_env
|
||||
options = {}
|
||||
options['u'] = spec[:username] if spec[:username]
|
||||
options['p'] = spec[:password] if spec[:password]
|
||||
options['S'] = spec[:sock] if spec[:sock]
|
||||
options_str = options.map { |key, value| "-#{key}#{value}" }.join(" ")
|
||||
ENV['cpk_adapter_options_str'] = options_str
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
namespace :oracle do
|
||||
desc 'Build the Oracle test databases'
|
||||
task :build_databases => :load_connection do
|
||||
puts File.join(SCHEMA_PATH, 'oracle.sql')
|
||||
options_str = ENV['cpk_adapter_options_str']
|
||||
sh %( sqlplus #{options_str} < #{File.join(SCHEMA_PATH, 'oracle.sql')} )
|
||||
end
|
||||
|
||||
desc 'Drop the Oracle test databases'
|
||||
task :drop_databases => :load_connection do
|
||||
puts File.join(SCHEMA_PATH, 'oracle.drop.sql')
|
||||
options_str = ENV['cpk_adapter_options_str']
|
||||
sh %( sqlplus #{options_str} < #{File.join(SCHEMA_PATH, 'oracle.drop.sql')} )
|
||||
end
|
||||
|
||||
desc 'Rebuild the Oracle test databases'
|
||||
task :rebuild_databases => [:drop_databases, :build_databases]
|
||||
|
||||
task :load_connection do
|
||||
require File.join(PROJECT_ROOT, %w[lib adapter_helper oracle])
|
||||
spec = AdapterHelper::Oracle.load_connection_from_env
|
||||
ENV['cpk_adapter_options_str'] = "#{spec[:username]}/#{spec[:password]}@#{spec[:host]}"
|
||||
end
|
||||
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
namespace :postgresql do
|
||||
desc 'Build the PostgreSQL test databases'
|
||||
task :build_databases => :load_connection do
|
||||
sh %{ createdb "#{GEM_NAME}_unittest" }
|
||||
sh %{ psql "#{GEM_NAME}_unittest" -f #{File.join(SCHEMA_PATH, 'postgresql.sql')} }
|
||||
end
|
||||
|
||||
desc 'Drop the PostgreSQL test databases'
|
||||
task :drop_databases => :load_connection do
|
||||
sh %{ dropdb "#{GEM_NAME}_unittest" }
|
||||
end
|
||||
|
||||
desc 'Rebuild the PostgreSQL test databases'
|
||||
task :rebuild_databases => [:drop_databases, :build_databases]
|
||||
|
||||
task :load_connection do
|
||||
require File.join(PROJECT_ROOT, %w[lib adapter_helper postgresql])
|
||||
spec = AdapterHelper::Postgresql.load_connection_from_env
|
||||
options = {}
|
||||
options['u'] = spec[:username] if spec[:username]
|
||||
options['p'] = spec[:password] if spec[:password]
|
||||
options_str = options.map { |key, value| "-#{key}#{value}" }.join(" ")
|
||||
ENV['cpk_adapter_options_str'] = options_str
|
||||
end
|
||||
end
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
namespace :sqlite3 do
|
||||
desc 'Build the sqlite test databases'
|
||||
task :build_databases => :load_connection do
|
||||
file = File.join(SCHEMA_PATH, 'sqlite.sql')
|
||||
dbfile = File.join(PROJECT_ROOT, ENV['cpk_adapter_options_str'])
|
||||
cmd = "mkdir -p #{File.dirname(dbfile)}"
|
||||
puts cmd
|
||||
sh %{ #{cmd} }
|
||||
cmd = "sqlite3 #{dbfile} < #{file}"
|
||||
puts cmd
|
||||
sh %{ #{cmd} }
|
||||
end
|
||||
|
||||
desc 'Drop the sqlite test databases'
|
||||
task :drop_databases => :load_connection do
|
||||
dbfile = ENV['cpk_adapter_options_str']
|
||||
sh %{ rm -f #{dbfile} }
|
||||
end
|
||||
|
||||
desc 'Rebuild the sqlite test databases'
|
||||
task :rebuild_databases => [:drop_databases, :build_databases]
|
||||
|
||||
task :load_connection do
|
||||
require File.join(PROJECT_ROOT, %w[lib adapter_helper sqlite3])
|
||||
spec = AdapterHelper::Sqlite3.load_connection_from_env
|
||||
ENV['cpk_adapter_options_str'] = spec[:dbfile]
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
desc 'Release the website and new gem version'
|
||||
task :deploy => [:check_version, :website, :release] do
|
||||
puts "Remember to create SVN tag:"
|
||||
puts "svn copy svn+ssh://#{RUBYFORGE_USERNAME}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
||||
"svn+ssh://#{RUBYFORGE_USERNAME}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
||||
puts "Suggested comment:"
|
||||
puts "Tagging release #{CHANGES}"
|
||||
end
|
||||
|
||||
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
|
||||
task :local_deploy => [:website_generate, :install_gem]
|
||||
|
||||
task :check_version do
|
||||
unless ENV['VERSION']
|
||||
puts 'Must pass a VERSION=x.y.z release version'
|
||||
exit
|
||||
end
|
||||
unless ENV['VERSION'] == VERS
|
||||
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
||||
exit
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
namespace :local do
|
||||
desc 'Copies over the same local files ready for editing'
|
||||
task :setup do
|
||||
sample_files = Dir[File.join(PROJECT_ROOT, "local/*.rb.sample")]
|
||||
sample_files.each do |sample_file|
|
||||
file = sample_file.sub(".sample","")
|
||||
unless File.exists?(file)
|
||||
puts "Copying #{sample_file} -> #{file}"
|
||||
sh %{ cp #{sample_file} #{file} }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
desc 'Generate website files'
|
||||
task :website_generate do
|
||||
sh %{ ruby scripts/txt2html website/index.txt > website/index.html }
|
||||
sh %{ ruby scripts/txt2js website/version.txt > website/version.js }
|
||||
sh %{ ruby scripts/txt2js website/version-raw.txt > website/version-raw.js }
|
||||
end
|
||||
|
||||
desc 'Upload website files to rubyforge'
|
||||
task :website_upload do
|
||||
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
||||
host = "#{config["username"]}@rubyforge.org"
|
||||
remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/"
|
||||
local_dir = 'website'
|
||||
sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
|
||||
end
|
||||
|
||||
desc 'Generate and upload website files'
|
||||
task :website => [:website_generate, :website_upload, :publish_docs]
|
|
@ -1,67 +0,0 @@
|
|||
= Composite Primary Keys - Testing Readme
|
||||
|
||||
== Testing an adapter
|
||||
|
||||
There are tests available for the following adapters:
|
||||
|
||||
* ibmdb
|
||||
* mysql
|
||||
* oracle
|
||||
* postgresql
|
||||
* sqlite
|
||||
|
||||
To run the tests for on of the adapters, follow these steps (using mysql in the example):
|
||||
|
||||
* rake -T | grep mysql
|
||||
|
||||
rake mysql:build_databases # Build the MySQL test databases
|
||||
rake mysql:drop_databases # Drop the MySQL test databases
|
||||
rake mysql:rebuild_databases # Rebuild the MySQL test databases
|
||||
rake test_mysql # Run tests for test_mysql
|
||||
|
||||
* rake mysql:build_databases
|
||||
* rake test_mysql
|
||||
|
||||
== Testing against different ActiveRecord versions (or Edge Rails)
|
||||
|
||||
ActiveRecord is a RubyGem within Rails, and is constantly being improved/changed on
|
||||
its repository (http://dev.rubyonrails.org). These changes may create errors for the CPK
|
||||
gem. So, we need a way to test CPK against Edge Rails, as well as officially released RubyGems.
|
||||
|
||||
The default test (as above) uses the latest RubyGem in your cache.
|
||||
|
||||
You can select an older RubyGem version by running the following:
|
||||
|
||||
* rake ar:set VERSION=1.14.4 test_mysql
|
||||
|
||||
== Edge Rails
|
||||
|
||||
Before you can test CPK against Edge Rails, you must checkout a copy of edge rails somewhere (see http://dev.rubyonrails.org for for examples)
|
||||
|
||||
* cd /path/to/gems
|
||||
* svn co http://svn.rubyonrails.org/rails/trunk rails
|
||||
|
||||
Say the rails folder is /path/to/gems/rails
|
||||
|
||||
Three ways to run CPK tests for Edge Rails:
|
||||
|
||||
i) Run:
|
||||
|
||||
EDGE_RAILS_DIR=/path/to/gems/rails rake ar:edge test_mysql
|
||||
|
||||
ii) In your .profile, set the environment variable EDGE_RAILS_DIR=/path/to/gems/rails,
|
||||
and once you reload your profile, run:
|
||||
|
||||
rake ar:edge test_mysql
|
||||
|
||||
iii) Store the path in local/paths.rb. Run:
|
||||
|
||||
cp local/paths.rb.sample local/paths.rb
|
||||
# Now set ENV['EDGE_RAILS_DIR']=/path/to/gems/rails
|
||||
rake ar:edge test_mysql
|
||||
|
||||
These are all variations of the same theme:
|
||||
|
||||
* Set the environment variable EDGE_RAILS_DIR to the path to Rails (which contains the activerecord/lib folder)
|
||||
* Run: rake ar:edge test_<adapter>
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
$:.unshift(ENV['AR_LOAD_PATH']) if ENV['AR_LOAD_PATH']
|
||||
|
||||
require 'test/unit'
|
||||
require 'hash_tricks'
|
||||
require 'rubygems'
|
||||
require 'active_record'
|
||||
require 'active_record/fixtures'
|
||||
begin
|
||||
require 'connection'
|
||||
rescue MissingSourceFile => e
|
||||
adapter = 'postgresql' #'sqlite'
|
||||
require "#{File.dirname(__FILE__)}/connections/native_#{adapter}/connection"
|
||||
end
|
||||
require 'composite_primary_keys'
|
||||
|
||||
QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') unless Object.const_defined?(:QUOTED_TYPE)
|
||||
|
||||
class Test::Unit::TestCase #:nodoc:
|
||||
self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
||||
self.use_instantiated_fixtures = false
|
||||
self.use_transactional_fixtures = true
|
||||
|
||||
def assert_date_from_db(expected, actual, message = nil)
|
||||
# SQL Server doesn't have a separate column type just for dates,
|
||||
# so the time is in the string and incorrectly formatted
|
||||
if current_adapter?(:SQLServerAdapter)
|
||||
assert_equal expected.strftime("%Y/%m/%d 00:00:00"), actual.strftime("%Y/%m/%d 00:00:00")
|
||||
elsif current_adapter?(:SybaseAdapter)
|
||||
assert_equal expected.to_s, actual.to_date.to_s, message
|
||||
else
|
||||
assert_equal expected.to_s, actual.to_s, message
|
||||
end
|
||||
end
|
||||
|
||||
def assert_queries(num = 1)
|
||||
ActiveRecord::Base.connection.class.class_eval do
|
||||
self.query_count = 0
|
||||
alias_method :execute, :execute_with_query_counting
|
||||
end
|
||||
yield
|
||||
ensure
|
||||
ActiveRecord::Base.connection.class.class_eval do
|
||||
alias_method :execute, :execute_without_query_counting
|
||||
end
|
||||
assert_equal num, ActiveRecord::Base.connection.query_count, "#{ActiveRecord::Base.connection.query_count} instead of #{num} queries were executed."
|
||||
end
|
||||
|
||||
def assert_no_queries(&block)
|
||||
assert_queries(0, &block)
|
||||
end
|
||||
|
||||
cattr_accessor :classes
|
||||
protected
|
||||
|
||||
def testing_with(&block)
|
||||
classes.keys.each do |@key_test|
|
||||
@klass_info = classes[@key_test]
|
||||
@klass, @primary_keys = @klass_info[:class], @klass_info[:primary_keys]
|
||||
order = @klass.primary_key.is_a?(String) ? @klass.primary_key : @klass.primary_key.join(',')
|
||||
@first = @klass.find(:first, :order => order)
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
def first_id
|
||||
ids = (1..@primary_keys.length).map {|num| 1}
|
||||
composite? ? ids.to_composite_ids : ids.first
|
||||
end
|
||||
|
||||
def first_id_str
|
||||
composite? ? first_id.join(CompositePrimaryKeys::ID_SEP) : first_id.to_s
|
||||
end
|
||||
|
||||
def composite?
|
||||
@key_test != :single
|
||||
end
|
||||
end
|
||||
|
||||
def current_adapter?(type)
|
||||
ActiveRecord::ConnectionAdapters.const_defined?(type) &&
|
||||
ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters.const_get(type))
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connection.class.class_eval do
|
||||
cattr_accessor :query_count
|
||||
alias_method :execute_without_query_counting, :execute
|
||||
def execute_with_query_counting(sql, name = nil)
|
||||
self.query_count += 1
|
||||
execute_without_query_counting(sql, name)
|
||||
end
|
||||
end
|
||||
|
||||
#ActiveRecord::Base.logger = Logger.new(STDOUT)
|
||||
#ActiveRecord::Base.colorize_logging = false
|
|
@ -1,23 +0,0 @@
|
|||
print "Using IBM2 \n"
|
||||
require 'logger'
|
||||
|
||||
gem 'ibm_db'
|
||||
require 'IBM_DB'
|
||||
|
||||
RAILS_CONNECTION_ADAPTERS = %w( mysql postgresql sqlite firebird sqlserver db2 oracle sybase openbase frontbase ibm_db )
|
||||
|
||||
|
||||
ActiveRecord::Base.logger = Logger.new("debug.log")
|
||||
|
||||
db1 = 'composite_primary_keys_unittest'
|
||||
|
||||
connection_options = {
|
||||
:adapter => "ibm_db",
|
||||
:database => "ocdpdev",
|
||||
:username => "db2inst1",
|
||||
:password => "password",
|
||||
:host => '192.168.2.21'
|
||||
}
|
||||
|
||||
ActiveRecord::Base.configurations = { db1 => connection_options }
|
||||
ActiveRecord::Base.establish_connection(connection_options)
|
|
@ -1,13 +0,0 @@
|
|||
print "Using native MySQL\n"
|
||||
require 'fileutils'
|
||||
require 'logger'
|
||||
require 'adapter_helper/mysql'
|
||||
|
||||
log_path = File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. .. log]))
|
||||
FileUtils.mkdir_p log_path
|
||||
puts "Logging to #{log_path}/debug.log"
|
||||
ActiveRecord::Base.logger = Logger.new("#{log_path}/debug.log")
|
||||
|
||||
# Adapter config setup in locals/database_connections.rb
|
||||
connection_options = AdapterHelper::MySQL.load_connection_from_env
|
||||
ActiveRecord::Base.establish_connection(connection_options)
|
|
@ -1,14 +0,0 @@
|
|||
print "Using native Oracle\n"
|
||||
require 'fileutils'
|
||||
require 'logger'
|
||||
require 'adapter_helper/oracle'
|
||||
|
||||
log_path = File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. .. log]))
|
||||
FileUtils.mkdir_p log_path
|
||||
puts "Logging to #{log_path}/debug.log"
|
||||
ActiveRecord::Base.logger = Logger.new("#{log_path}/debug.log")
|
||||
|
||||
# Adapter config setup in locals/database_connections.rb
|
||||
connection_options = AdapterHelper::Oracle.load_connection_from_env
|
||||
puts connection_options.inspect
|
||||
ActiveRecord::Base.establish_connection(connection_options)
|
|
@ -1,9 +0,0 @@
|
|||
print "Using native Postgresql\n"
|
||||
require 'logger'
|
||||
require 'adapter_helper/postgresql'
|
||||
|
||||
ActiveRecord::Base.logger = Logger.new("debug.log")
|
||||
|
||||
# Adapter config setup in locals/database_connections.rb
|
||||
connection_options = AdapterHelper::Postgresql.load_connection_from_env
|
||||
ActiveRecord::Base.establish_connection(connection_options)
|
|
@ -1,9 +0,0 @@
|
|||
print "Using native Sqlite3\n"
|
||||
require 'logger'
|
||||
require 'adapter_helper/sqlite3'
|
||||
|
||||
ActiveRecord::Base.logger = Logger.new("debug.log")
|
||||
|
||||
# Adapter config setup in locals/database_connections.rb
|
||||
connection_options = AdapterHelper::Sqlite3.load_connection_from_env
|
||||
ActiveRecord::Base.establish_connection(connection_options)
|
|
@ -1,5 +0,0 @@
|
|||
class Article < ActiveRecord::Base
|
||||
has_many :readings
|
||||
has_many :users, :through => :readings
|
||||
end
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
first:
|
||||
id: 1
|
||||
name: Article One
|
||||
second:
|
||||
id: 2
|
||||
name: Article Two
|
|
@ -1,6 +0,0 @@
|
|||
class Comment < ActiveRecord::Base
|
||||
set_primary_keys :id
|
||||
belongs_to :person, :polymorphic => true
|
||||
belongs_to :hack
|
||||
end
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
comment1:
|
||||
id: 1
|
||||
person_id: 1
|
||||
person_type: Employee
|
||||
|
||||
comment2:
|
||||
id: 2
|
||||
person_id: 1
|
||||
person_type: User
|
||||
hack_id: andrew
|
||||
|
||||
comment3:
|
||||
id: 3
|
||||
person_id: andrew
|
||||
person_type: Hack
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
CREATE TABLE reference_types (
|
||||
reference_type_id integer NOT NULL generated by default as identity (start with 100, increment by 1, no cache),
|
||||
type_label varchar(50) default NULL,
|
||||
abbreviation varchar(50) default NULL,
|
||||
description varchar(50) default NULL,
|
||||
PRIMARY KEY (reference_type_id)
|
||||
);
|
||||
|
||||
CREATE TABLE reference_codes (
|
||||
reference_type_id integer,
|
||||
reference_code integer NOT NULL,
|
||||
code_label varchar(50) default NULL,
|
||||
abbreviation varchar(50) default NULL,
|
||||
description varchar(50) default NULL,
|
||||
PRIMARY KEY (reference_type_id,reference_code)
|
||||
);
|
||||
|
||||
CREATE TABLE products (
|
||||
id integer NOT NULL,
|
||||
name varchar(50) default NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE tariffs (
|
||||
tariff_id integer NOT NULL,
|
||||
start_date date NOT NULL,
|
||||
amount integer default NULL,
|
||||
PRIMARY KEY (tariff_id,start_date)
|
||||
);
|
||||
|
||||
CREATE TABLE product_tariffs (
|
||||
product_id integer NOT NULL,
|
||||
tariff_id integer NOT NULL,
|
||||
tariff_start_date date NOT NULL,
|
||||
PRIMARY KEY (product_id,tariff_id,tariff_start_date)
|
||||
);
|
||||
|
||||
CREATE TABLE suburbs (
|
||||
city_id integer NOT NULL,
|
||||
suburb_id integer NOT NULL,
|
||||
name varchar(50) NOT NULL,
|
||||
PRIMARY KEY (city_id,suburb_id)
|
||||
);
|
||||
|
||||
CREATE TABLE streets (
|
||||
id integer NOT NULL ,
|
||||
city_id integer NOT NULL,
|
||||
suburb_id integer NOT NULL,
|
||||
name varchar(50) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
id integer NOT NULL ,
|
||||
name varchar(50) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE articles (
|
||||
id integer NOT NULL ,
|
||||
name varchar(50) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE readings (
|
||||
id integer NOT NULL ,
|
||||
user_id integer NOT NULL,
|
||||
article_id integer NOT NULL,
|
||||
rating integer NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE groups (
|
||||
id integer NOT NULL ,
|
||||
name varchar(50) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE memberships (
|
||||
user_id integer NOT NULL,
|
||||
group_id integer NOT NULL,
|
||||
PRIMARY KEY (user_id,group_id)
|
||||
);
|
||||
|
||||
CREATE TABLE membership_statuses (
|
||||
id integer NOT NULL ,
|
||||
user_id integer NOT NULL,
|
||||
group_id integer NOT NULL,
|
||||
status varchar(50) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
create table kitchen_sinks (
|
||||
id_1 integer not null,
|
||||
id_2 integer not null,
|
||||
a_date date,
|
||||
a_string varchar(100),
|
||||
primary key (id_1, id_2)
|
||||
);
|
||||
|
||||
create table restaurants (
|
||||
franchise_id integer not null,
|
||||
store_id integer not null,
|
||||
name varchar(100),
|
||||
primary key (franchise_id, store_id)
|
||||
);
|
||||
|
||||
create table restaurants_suburbs (
|
||||
franchise_id integer not null,
|
||||
store_id integer not null,
|
||||
city_id integer not null,
|
||||
suburb_id integer not null
|
||||
);
|
|
@ -1,16 +0,0 @@
|
|||
drop table MEMBERSHIPS;
|
||||
drop table REFERENCE_CODES;
|
||||
drop table TARIFFS;
|
||||
drop table ARTICLES;
|
||||
drop table GROUPS;
|
||||
drop table MEMBERSHIP_STATUSES;
|
||||
drop table READINGS;
|
||||
drop table REFERENCE_TYPES;
|
||||
drop table STREETS;
|
||||
drop table PRODUCTS;
|
||||
drop table USERS;
|
||||
drop table SUBURBS;
|
||||
drop table PRODUCT_TARIFFS;
|
||||
drop table KITCHEN_SINK;
|
||||
drop table RESTAURANTS;
|
||||
drop table RESTAURANTS_SUBURBS;
|
|
@ -1,174 +0,0 @@
|
|||
create table reference_types (
|
||||
reference_type_id int(11) not null auto_increment,
|
||||
type_label varchar(50) default null,
|
||||
abbreviation varchar(50) default null,
|
||||
description varchar(50) default null,
|
||||
primary key (reference_type_id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table reference_codes (
|
||||
reference_type_id int(11),
|
||||
reference_code int(11) not null,
|
||||
code_label varchar(50) default null,
|
||||
abbreviation varchar(50) default null,
|
||||
description varchar(50) default null,
|
||||
primary key (reference_type_id, reference_code)
|
||||
) type=InnoDB;
|
||||
|
||||
create table products (
|
||||
id int(11) not null auto_increment,
|
||||
name varchar(50) default null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table tariffs (
|
||||
tariff_id int(11) not null,
|
||||
start_date date not null,
|
||||
amount integer(11) default null,
|
||||
primary key (tariff_id, start_date)
|
||||
) type=InnoDB;
|
||||
|
||||
create table product_tariffs (
|
||||
product_id int(11) not null,
|
||||
tariff_id int(11) not null,
|
||||
tariff_start_date date not null,
|
||||
primary key (product_id, tariff_id, tariff_start_date)
|
||||
) type=InnoDB;
|
||||
|
||||
create table suburbs (
|
||||
city_id int(11) not null,
|
||||
suburb_id int(11) not null,
|
||||
name varchar(50) not null,
|
||||
primary key (city_id, suburb_id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table streets (
|
||||
id int(11) not null auto_increment,
|
||||
city_id int(11) not null,
|
||||
suburb_id int(11) not null,
|
||||
name varchar(50) not null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table users (
|
||||
id int(11) not null auto_increment,
|
||||
name varchar(50) not null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table articles (
|
||||
id int(11) not null auto_increment,
|
||||
name varchar(50) not null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table readings (
|
||||
id int(11) not null auto_increment,
|
||||
user_id int(11) not null,
|
||||
article_id int(11) not null,
|
||||
rating int(11) not null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table groups (
|
||||
id int(11) not null auto_increment,
|
||||
name varchar(50) not null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table memberships (
|
||||
user_id int(11) not null,
|
||||
group_id int(11) not null,
|
||||
primary key (user_id,group_id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table membership_statuses (
|
||||
id int(11) not null auto_increment,
|
||||
user_id int(11) not null,
|
||||
group_id int(11) not null,
|
||||
status varchar(50) not null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table departments (
|
||||
department_id int(11) not null,
|
||||
location_id int(11) not null,
|
||||
primary key (department_id, location_id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table employees (
|
||||
id int(11) not null auto_increment,
|
||||
department_id int(11) default null,
|
||||
location_id int(11) default null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table comments (
|
||||
id int(11) not null auto_increment,
|
||||
person_id varchar(100) default null,
|
||||
person_type varchar(100) default null,
|
||||
hack_id varchar(100) default null,
|
||||
primary key (id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table hacks (
|
||||
name varchar(50) not null,
|
||||
primary key (name)
|
||||
) type=InnoDB;
|
||||
|
||||
create table kitchen_sinks (
|
||||
id_1 int(11) not null,
|
||||
id_2 int(11) not null,
|
||||
a_date date,
|
||||
a_string varchar(100),
|
||||
primary key (id_1, id_2)
|
||||
) type=InnoDB;
|
||||
|
||||
create table restaurants (
|
||||
franchise_id int(11) not null,
|
||||
store_id int(11) not null,
|
||||
name varchar(100),
|
||||
primary key (franchise_id, store_id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table restaurants_suburbs (
|
||||
franchise_id int(11) not null,
|
||||
store_id int(11) not null,
|
||||
city_id int(11) not null,
|
||||
suburb_id int(11) not null
|
||||
) type=InnoDB;
|
||||
|
||||
create table dorms (
|
||||
id int(11) not null auto_increment,
|
||||
primary key(id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table rooms (
|
||||
dorm_id int(11) not null,
|
||||
room_id int(11) not null,
|
||||
primary key (dorm_id, room_id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table room_attributes (
|
||||
id int(11) not null auto_increment,
|
||||
name varchar(50),
|
||||
primary key(id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table room_attribute_assignments (
|
||||
dorm_id int(11) not null,
|
||||
room_id int(11) not null,
|
||||
room_attribute_id int(11) not null
|
||||
) type=InnoDB;
|
||||
|
||||
create table students (
|
||||
id int(11) not null auto_increment,
|
||||
primary key(id)
|
||||
) type=InnoDB;
|
||||
|
||||
create table room_assignments (
|
||||
student_id int(11) not null,
|
||||
dorm_id int(11) not null,
|
||||
room_id int(11) not null
|
||||
) type=InnoDB;
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
drop table reference_types;
|
||||
drop sequence reference_types_seq;
|
||||
drop table reference_codes;
|
||||
drop table products;
|
||||
drop sequence products_seq;
|
||||
drop table tariffs;
|
||||
drop table product_tariffs;
|
||||
drop table suburbs;
|
||||
drop table streets;
|
||||
drop sequence streets_seq;
|
||||
drop table users;
|
||||
drop sequence users_seq;
|
||||
drop table articles;
|
||||
drop sequence articles_seq;
|
||||
drop table readings;
|
||||
drop sequence readings_seq;
|
||||
drop table groups;
|
||||
drop sequence groups_seq;
|
||||
drop table memberships;
|
||||
drop table membership_statuses;
|
||||
drop sequence membership_statuses_seq;
|
||||
drop table departments;
|
||||
drop table employees;
|
||||
drop sequence employees_seq;
|
||||
drop table comments;
|
||||
drop sequence comments_seq;
|
||||
drop table hacks;
|
||||
drop table kitchen_sinks;
|
||||
drop table restaurants;
|
||||
drop table restaurants_suburbs;
|
||||
drop table dorms;
|
||||
drop sequence dorms_seq;
|
||||
drop table rooms;
|
||||
drop table room_attributes;
|
||||
drop sequence room_attributes_seq;
|
||||
drop table room_attribute_assignments;
|
||||
drop table room_assignments;
|
||||
drop table students;
|
||||
drop sequence students_seq;
|
|
@ -1,188 +0,0 @@
|
|||
create sequence reference_types_seq start with 1000;
|
||||
|
||||
create table reference_types (
|
||||
reference_type_id number(11) primary key,
|
||||
type_label varchar2(50) default null,
|
||||
abbreviation varchar2(50) default null,
|
||||
description varchar2(50) default null
|
||||
);
|
||||
|
||||
create table reference_codes (
|
||||
reference_type_id number(11),
|
||||
reference_code number(11),
|
||||
code_label varchar2(50) default null,
|
||||
abbreviation varchar2(50) default null,
|
||||
description varchar2(50) default null
|
||||
);
|
||||
|
||||
create sequence products_seq start with 1000;
|
||||
|
||||
create table products (
|
||||
id number(11) primary key,
|
||||
name varchar2(50) default null
|
||||
);
|
||||
|
||||
create table tariffs (
|
||||
tariff_id number(11),
|
||||
start_date date,
|
||||
amount number(11) default null,
|
||||
constraint tariffs_pk primary key (tariff_id, start_date)
|
||||
);
|
||||
|
||||
create table product_tariffs (
|
||||
product_id number(11),
|
||||
tariff_id number(11),
|
||||
tariff_start_date date,
|
||||
constraint product_tariffs_pk primary key (product_id, tariff_id, tariff_start_date)
|
||||
);
|
||||
|
||||
create table suburbs (
|
||||
city_id number(11),
|
||||
suburb_id number(11),
|
||||
name varchar2(50) not null,
|
||||
constraint suburbs_pk primary key (city_id, suburb_id)
|
||||
);
|
||||
|
||||
create sequence streets_seq start with 1000;
|
||||
|
||||
create table streets (
|
||||
id number(11) primary key,
|
||||
city_id number(11) not null,
|
||||
suburb_id number(11) not null,
|
||||
name varchar2(50) not null
|
||||
);
|
||||
|
||||
create sequence users_seq start with 1000;
|
||||
|
||||
create table users (
|
||||
id number(11) primary key,
|
||||
name varchar2(50) not null
|
||||
);
|
||||
|
||||
create sequence articles_seq start with 1000;
|
||||
|
||||
create table articles (
|
||||
id number(11) primary key,
|
||||
name varchar2(50) not null
|
||||
);
|
||||
|
||||
create sequence readings_seq start with 1000;
|
||||
|
||||
create table readings (
|
||||
id number(11) primary key,
|
||||
user_id number(11) not null,
|
||||
article_id number(11) not null,
|
||||
rating number(11) not null
|
||||
);
|
||||
|
||||
create sequence groups_seq start with 1000;
|
||||
|
||||
create table groups (
|
||||
id number(11) primary key,
|
||||
name varchar2(50) not null
|
||||
);
|
||||
|
||||
create table memberships (
|
||||
user_id number(11) not null,
|
||||
group_id number(11) not null,
|
||||
constraint memberships_pk primary key (user_id, group_id)
|
||||
);
|
||||
|
||||
create sequence membership_statuses_seq start with 1000;
|
||||
|
||||
create table membership_statuses (
|
||||
id number(11) primary key,
|
||||
user_id number(11) not null,
|
||||
group_id number(11) not null,
|
||||
status varchar2(50) not null
|
||||
);
|
||||
|
||||
create table departments (
|
||||
department_id number(11) not null,
|
||||
location_id number(11) not null,
|
||||
constraint departments_pk primary key (department_id, location_id)
|
||||
);
|
||||
|
||||
create sequence employees_seq start with 1000;
|
||||
|
||||
create table employees (
|
||||
id number(11) not null primary key,
|
||||
department_id number(11) default null,
|
||||
location_id number(11) default null
|
||||
);
|
||||
|
||||
create sequence comments_seq start with 1000;
|
||||
|
||||
create table comments (
|
||||
id number(11) not null primary key,
|
||||
person_id varchar(100) default null,
|
||||
person_type varchar(100) default null,
|
||||
hack_id varchar(100) default null
|
||||
);
|
||||
|
||||
create table hacks (
|
||||
name varchar(50) not null primary key
|
||||
);
|
||||
|
||||
create table kitchen_sinks (
|
||||
id_1 number(11) not null,
|
||||
id_2 number(11) not null,
|
||||
a_date date,
|
||||
a_string varchar(100),
|
||||
constraint kitchen_sinks_pk primary key (id_1, id_2)
|
||||
);
|
||||
|
||||
create table restaurants (
|
||||
franchise_id number(11) not null,
|
||||
store_id number(11) not null,
|
||||
name varchar(100),
|
||||
constraint restaurants_pk primary key (franchise_id, store_id)
|
||||
);
|
||||
|
||||
create table restaurants_suburbs (
|
||||
franchise_id number(11) not null,
|
||||
store_id number(11) not null,
|
||||
city_id number(11) not null,
|
||||
suburb_id number(11) not null
|
||||
);
|
||||
|
||||
create sequence dorms_seq start with 1000;
|
||||
|
||||
create table dorms (
|
||||
id number(11) not null,
|
||||
constraint dorms_pk primary key (id)
|
||||
);
|
||||
|
||||
create table rooms (
|
||||
dorm_id number(11) not null,
|
||||
room_id number(11) not null,
|
||||
constraint rooms_pk primary key (dorm_id, room_id)
|
||||
);
|
||||
|
||||
create sequence room_attributes_seq start with 1000;
|
||||
|
||||
create table room_attributes (
|
||||
id number(11) not null,
|
||||
name varchar(50),
|
||||
constraint room_attributes_pk primary key (id)
|
||||
);
|
||||
|
||||
create table room_attribute_assignments (
|
||||
dorm_id number(11) not null,
|
||||
room_id number(11) not null,
|
||||
room_attribute_id number(11) not null
|
||||
);
|
||||
|
||||
create sequence students_seq start with 1000;
|
||||
|
||||
create table students (
|
||||
id number(11) not null,
|
||||
constraint students_pk primary key (id)
|
||||
);
|
||||
|
||||
create table room_assignments (
|
||||
student_id number(11) not null,
|
||||
dorm_id number(11) not null,
|
||||
room_id number(11) not null
|
||||
);
|
||||
|
|
@ -1,199 +0,0 @@
|
|||
create sequence public.reference_types_seq start 1000;
|
||||
|
||||
create table reference_types (
|
||||
reference_type_id int default nextval('public.reference_types_seq'),
|
||||
type_label varchar(50) default null,
|
||||
abbreviation varchar(50) default null,
|
||||
description varchar(50) default null,
|
||||
primary key (reference_type_id)
|
||||
);
|
||||
|
||||
create table reference_codes (
|
||||
reference_type_id int,
|
||||
reference_code int not null,
|
||||
code_label varchar(50) default null,
|
||||
abbreviation varchar(50) default null,
|
||||
description varchar(50) default null
|
||||
);
|
||||
|
||||
create sequence public.products_seq start 1000;
|
||||
|
||||
create table products (
|
||||
id int not null default nextval('public.products_seq'),
|
||||
name varchar(50) default null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table tariffs (
|
||||
tariff_id int not null,
|
||||
start_date date not null,
|
||||
amount int default null,
|
||||
primary key (tariff_id, start_date)
|
||||
);
|
||||
|
||||
create table product_tariffs (
|
||||
product_id int not null,
|
||||
tariff_id int not null,
|
||||
tariff_start_date date not null,
|
||||
primary key (product_id, tariff_id, tariff_start_date)
|
||||
);
|
||||
|
||||
create table suburbs (
|
||||
city_id int not null,
|
||||
suburb_id int not null,
|
||||
name varchar(50) not null,
|
||||
primary key (city_id, suburb_id)
|
||||
);
|
||||
|
||||
create sequence public.streets_seq start 1000;
|
||||
|
||||
create table streets (
|
||||
id int not null default nextval('public.streets_seq'),
|
||||
city_id int not null,
|
||||
suburb_id int not null,
|
||||
name varchar(50) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create sequence public.users_seq start 1000;
|
||||
|
||||
create table users (
|
||||
id int not null default nextval('public.users_seq'),
|
||||
name varchar(50) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create sequence public.articles_seq start 1000;
|
||||
|
||||
create table articles (
|
||||
id int not null default nextval('public.articles_seq'),
|
||||
name varchar(50) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create sequence public.readings_seq start 1000;
|
||||
|
||||
create table readings (
|
||||
id int not null default nextval('public.readings_seq'),
|
||||
user_id int not null,
|
||||
article_id int not null,
|
||||
rating int not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create sequence public.groups_seq start 1000;
|
||||
|
||||
create table groups (
|
||||
id int not null default nextval('public.groups_seq'),
|
||||
name varchar(50) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table memberships (
|
||||
user_id int not null,
|
||||
group_id int not null,
|
||||
primary key (user_id, group_id)
|
||||
);
|
||||
|
||||
create sequence public.membership_statuses_seq start 1000;
|
||||
|
||||
create table membership_statuses (
|
||||
id int not null default nextval('public.membership_statuses_seq'),
|
||||
user_id int not null,
|
||||
group_id int not null,
|
||||
status varchar(50) not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table departments (
|
||||
department_id int not null,
|
||||
location_id int not null,
|
||||
primary key (department_id, location_id)
|
||||
);
|
||||
|
||||
create sequence public.employees_seq start 1000;
|
||||
|
||||
create table employees (
|
||||
id int not null default nextval('public.employees_seq'),
|
||||
department_id int default null,
|
||||
location_id int default null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create sequence public.comments_seq start 1000;
|
||||
|
||||
create table comments (
|
||||
id int not null default nextval('public.comments_seq'),
|
||||
person_id varchar(100) default null,
|
||||
person_type varchar(100) default null,
|
||||
hack_id varchar(100) default null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table hacks (
|
||||
name varchar(50) not null,
|
||||
primary key (name)
|
||||
);
|
||||
|
||||
create table kitchen_sinks (
|
||||
id_1 int not null,
|
||||
id_2 int not null,
|
||||
a_date date,
|
||||
a_string varchar(100),
|
||||
primary key (id_1, id_2)
|
||||
);
|
||||
|
||||
create table restaurants (
|
||||
franchise_id int not null,
|
||||
store_id int not null,
|
||||
name varchar(100),
|
||||
primary key (franchise_id, store_id)
|
||||
);
|
||||
|
||||
create table restaurants_suburbs (
|
||||
franchise_id int not null,
|
||||
store_id int not null,
|
||||
city_id int not null,
|
||||
suburb_id int not null
|
||||
);
|
||||
|
||||
create sequence public.dorms_seq start 1000;
|
||||
|
||||
create table dorms (
|
||||
id int not null default nextval('public.dorms_seq'),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table rooms (
|
||||
dorm_id int not null,
|
||||
room_id int not null,
|
||||
primary key (dorm_id, room_id)
|
||||
);
|
||||
|
||||
create sequence public.room_attributes_seq start 1000;
|
||||
|
||||
create table room_attributes (
|
||||
id int not null default nextval('public.room_attributes_seq'),
|
||||
name varchar(50),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table room_attribute_assignments (
|
||||
dorm_id int not null,
|
||||
room_id int not null,
|
||||
room_attribute_id int not null
|
||||
);
|
||||
|
||||
create sequence public.students_seq start 1000;
|
||||
|
||||
create table students (
|
||||
id int not null default nextval('public.students_seq'),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table room_assignments (
|
||||
student_id int not null,
|
||||
dorm_id int not null,
|
||||
room_id int not null
|
||||
);
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
create table reference_types (
|
||||
reference_type_id integer primary key,
|
||||
type_label varchar(50) default null,
|
||||
abbreviation varchar(50) default null,
|
||||
description varchar(50) default null
|
||||
);
|
||||
|
||||
create table reference_codes (
|
||||
reference_type_id int(11),
|
||||
reference_code int(11) not null,
|
||||
code_label varchar(50) default null,
|
||||
abbreviation varchar(50) default null,
|
||||
description varchar(50) default null,
|
||||
primary key (reference_type_id, reference_code)
|
||||
);
|
||||
|
||||
create table products (
|
||||
id int(11) not null primary key,
|
||||
name varchar(50) default null
|
||||
);
|
||||
|
||||
create table tariffs (
|
||||
tariff_id int(11) not null,
|
||||
start_date date not null,
|
||||
amount integer(11) default null,
|
||||
primary key (tariff_id, start_date)
|
||||
);
|
||||
|
||||
create table product_tariffs (
|
||||
product_id int(11) not null,
|
||||
tariff_id int(11) not null,
|
||||
tariff_start_date date not null,
|
||||
primary key (product_id, tariff_id, tariff_start_date)
|
||||
);
|
||||
|
||||
create table suburbs (
|
||||
city_id int(11) not null,
|
||||
suburb_id int(11) not null,
|
||||
name varchar(50) not null,
|
||||
primary key (city_id, suburb_id)
|
||||
);
|
||||
|
||||
create table streets (
|
||||
id integer not null primary key autoincrement,
|
||||
city_id int(11) not null,
|
||||
suburb_id int(11) not null,
|
||||
name varchar(50) not null
|
||||
);
|
||||
|
||||
create table users (
|
||||
id integer not null primary key autoincrement,
|
||||
name varchar(50) not null
|
||||
);
|
||||
|
||||
create table articles (
|
||||
id integer not null primary key autoincrement,
|
||||
name varchar(50) not null
|
||||
);
|
||||
|
||||
create table readings (
|
||||
id integer not null primary key autoincrement,
|
||||
user_id int(11) not null,
|
||||
article_id int(11) not null,
|
||||
rating int(11) not null
|
||||
);
|
||||
|
||||
create table groups (
|
||||
id integer not null primary key autoincrement,
|
||||
name varchar(50) not null
|
||||
);
|
||||
|
||||
create table memberships (
|
||||
user_id int not null,
|
||||
group_id int not null,
|
||||
primary key (user_id, group_id)
|
||||
);
|
||||
|
||||
create table membership_statuses (
|
||||
id integer not null primary key autoincrement,
|
||||
user_id int not null,
|
||||
group_id int not null,
|
||||
status varchar(50) not null
|
||||
);
|
||||
|
||||
create table departments (
|
||||
department_id integer not null,
|
||||
location_id integer not null,
|
||||
primary key (department_id, location_id)
|
||||
);
|
||||
|
||||
create table employees (
|
||||
id integer not null primary key autoincrement,
|
||||
department_id integer null,
|
||||
location_id integer null
|
||||
);
|
||||
|
||||
create table comments (
|
||||
id integer not null primary key autoincrement,
|
||||
person_id varchar(100) null,
|
||||
person_type varchar(100) null,
|
||||
hack_id varchar(100) null
|
||||
);
|
||||
|
||||
create table hacks (
|
||||
name varchar(50) not null primary key
|
||||
);
|
||||
|
||||
create table kitchen_sinks (
|
||||
id_1 integer not null,
|
||||
id_2 integer not null,
|
||||
a_date date,
|
||||
a_string varchar(100),
|
||||
primary key (id_1, id_2)
|
||||
);
|
||||
|
||||
create table restaurants (
|
||||
franchise_id integer not null,
|
||||
store_id integer not null,
|
||||
name varchar(100),
|
||||
primary key (franchise_id, store_id)
|
||||
);
|
||||
|
||||
create table restaurants_suburbs (
|
||||
franchise_id integer not null,
|
||||
store_id integer not null,
|
||||
city_id integer not null,
|
||||
suburb_id integer not null
|
||||
);
|
||||
|
||||
create table dorms (
|
||||
id integer not null primary key autoincrement
|
||||
);
|
||||
|
||||
create table rooms (
|
||||
dorm_id integer not null,
|
||||
room_id integer not null,
|
||||
primary key (dorm_id, room_id)
|
||||
);
|
||||
|
||||
create table room_attributes (
|
||||
id integer not null primary key autoincrement,
|
||||
name varchar(50)
|
||||
);
|
||||
|
||||
create table room_attribute_assignments (
|
||||
dorm_id integer not null,
|
||||
room_id integer not null,
|
||||
room_attribute_id integer not null
|
||||
);
|
||||
|
||||
create table students (
|
||||
id integer not null primary key autoincrement
|
||||
);
|
||||
|
||||
create table room_assignments (
|
||||
student_id integer not null,
|
||||
dorm_id integer not null,
|
||||
room_id integer not null
|
||||
);
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
class Department < ActiveRecord::Base
|
||||
# set_primary_keys *keys - turns on composite key functionality
|
||||
set_primary_keys :department_id, :location_id
|
||||
has_many :employees, :foreign_key => [:department_id, :location_id]
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
department1-cpk:
|
||||
department_id: 1
|
||||
location_id: 1
|
|
@ -1,4 +0,0 @@
|
|||
class Employee < ActiveRecord::Base
|
||||
belongs_to :department, :foreign_key => [:department_id, :location_id]
|
||||
has_many :comments, :as => :person
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
employee1:
|
||||
id: 1
|
||||
department_id: 1
|
||||
location_id: 1
|
||||
employee2:
|
||||
id: 2
|
||||
department_id: 1
|
||||
location_id: 1
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
class Group < ActiveRecord::Base
|
||||
has_many :memberships
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
cpk:
|
||||
id: 1
|
||||
name: Composite Primary Keys
|
|
@ -1,6 +0,0 @@
|
|||
class Hack < ActiveRecord::Base
|
||||
set_primary_keys :name
|
||||
has_many :comments, :as => :person
|
||||
|
||||
has_one :first_comment, :as => :person, :class_name => "Comment"
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
andrew:
|
||||
name: andrew
|
|
@ -1,7 +0,0 @@
|
|||
class Membership < ActiveRecord::Base
|
||||
# set_primary_keys *keys - turns on composite key functionality
|
||||
set_primary_keys :user_id, :group_id
|
||||
belongs_to :user
|
||||
belongs_to :group
|
||||
has_many :statuses, :class_name => 'MembershipStatus', :foreign_key => [:user_id, :group_id]
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
class MembershipStatus < ActiveRecord::Base
|
||||
belongs_to :membership, :foreign_key => [:user_id, :group_id]
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
santiago-cpk:
|
||||
id: 1
|
||||
user_id: 1
|
||||
group_id: 1
|
||||
status: Active
|
||||
drnic-cpk:
|
||||
id: 2
|
||||
user_id: 2
|
||||
group_id: 1
|
||||
status: Owner
|
|
@ -1,6 +0,0 @@
|
|||
santiago-cpk:
|
||||
user_id: 1
|
||||
group_id: 1
|
||||
drnic-cpk:
|
||||
user_id: 2
|
||||
group_id: 1
|
|
@ -1,7 +0,0 @@
|
|||
class Product < ActiveRecord::Base
|
||||
set_primary_keys :id # redundant
|
||||
has_many :product_tariffs, :foreign_key => :product_id
|
||||
has_one :product_tariff, :foreign_key => :product_id
|
||||
|
||||
has_many :tariffs, :through => :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
class ProductTariff < ActiveRecord::Base
|
||||
set_primary_keys :product_id, :tariff_id, :tariff_start_date
|
||||
belongs_to :product, :foreign_key => :product_id
|
||||
belongs_to :tariff, :foreign_key => [:tariff_id, :tariff_start_date]
|
||||
end
|
|
@ -1,12 +0,0 @@
|
|||
first_flat:
|
||||
product_id: 1
|
||||
tariff_id: 1
|
||||
tariff_start_date: <%= Date.today.to_s(:db) %>
|
||||
first_free:
|
||||
product_id: 1
|
||||
tariff_id: 2
|
||||
tariff_start_date: <%= Date.today.to_s(:db) %>
|
||||
second_free:
|
||||
product_id: 2
|
||||
tariff_id: 2
|
||||
tariff_start_date: <%= Date.today.to_s(:db) %>
|
|
@ -1,6 +0,0 @@
|
|||
first_product:
|
||||
id: 1
|
||||
name: Product One
|
||||
second_product:
|
||||
id: 2
|
||||
name: Product Two
|
|
@ -1,4 +0,0 @@
|
|||
class Reading < ActiveRecord::Base
|
||||
belongs_to :article
|
||||
belongs_to :user
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
santiago_first:
|
||||
id: 1
|
||||
user_id: 1
|
||||
article_id: 1
|
||||
rating: 4
|
||||
santiago_second:
|
||||
id: 2
|
||||
user_id: 1
|
||||
article_id: 2
|
||||
rating: 5
|
|
@ -1,7 +0,0 @@
|
|||
class ReferenceCode < ActiveRecord::Base
|
||||
set_primary_keys :reference_type_id, :reference_code
|
||||
|
||||
belongs_to :reference_type, :foreign_key => "reference_type_id"
|
||||
|
||||
validates_presence_of :reference_code, :code_label, :abbreviation
|
||||
end
|
|
@ -1,28 +0,0 @@
|
|||
name_prefix_mr:
|
||||
reference_type_id: 1
|
||||
reference_code: 1
|
||||
code_label: MR
|
||||
abbreviation: Mr
|
||||
name_prefix_mrs:
|
||||
reference_type_id: 1
|
||||
reference_code: 2
|
||||
code_label: MRS
|
||||
abbreviation: Mrs
|
||||
name_prefix_ms:
|
||||
reference_type_id: 1
|
||||
reference_code: 3
|
||||
code_label: MS
|
||||
abbreviation: Ms
|
||||
|
||||
gender_male:
|
||||
reference_type_id: 2
|
||||
reference_code: 1
|
||||
code_label: MALE
|
||||
abbreviation: Male
|
||||
gender_female:
|
||||
reference_type_id: 2
|
||||
reference_code: 2
|
||||
code_label: FEMALE
|
||||
abbreviation: Female
|
||||
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
class ReferenceType < ActiveRecord::Base
|
||||
set_primary_key :reference_type_id
|
||||
has_many :reference_codes, :foreign_key => "reference_type_id"
|
||||
|
||||
validates_presence_of :type_label, :abbreviation
|
||||
validates_uniqueness_of :type_label
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
name_prefix:
|
||||
reference_type_id: 1
|
||||
type_label: NAME_PREFIX
|
||||
abbreviation: Name Prefix
|
||||
|
||||
gender:
|
||||
reference_type_id: 2
|
||||
type_label: GENDER
|
||||
abbreviation: Gender
|
|
@ -1,3 +0,0 @@
|
|||
class Street < ActiveRecord::Base
|
||||
belongs_to :suburb, :foreign_key => [:city_id, :suburb_id]
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
first:
|
||||
id: 1
|
||||
city_id: 1
|
||||
suburb_id: 1
|
||||
name: First Street
|
||||
second1:
|
||||
id: 2
|
||||
city_id: 2
|
||||
suburb_id: 1
|
||||
name: First Street
|
||||
second2:
|
||||
id: 3
|
||||
city_id: 2
|
||||
suburb_id: 1
|
||||
name: Second Street
|
|
@ -1,6 +0,0 @@
|
|||
class Suburb < ActiveRecord::Base
|
||||
set_primary_keys :city_id, :suburb_id
|
||||
has_many :streets, :foreign_key => [:city_id, :suburb_id]
|
||||
has_many :first_streets, :foreign_key => [:city_id, :suburb_id],
|
||||
:class_name => 'Street', :conditions => "streets.name = 'First Street'"
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
first:
|
||||
city_id: 1
|
||||
suburb_id: 1
|
||||
name: First Suburb
|
||||
second:
|
||||
city_id: 2
|
||||
suburb_id: 1
|
||||
name: Second Suburb
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
class Tariff < ActiveRecord::Base
|
||||
set_primary_keys [:tariff_id, :start_date]
|
||||
has_many :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
|
||||
has_one :product_tariff, :foreign_key => [:tariff_id, :tariff_start_date]
|
||||
has_many :products, :through => :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
flat:
|
||||
tariff_id: 1
|
||||
start_date: <%= Date.today.to_s(:db) %>
|
||||
amount: 50
|
||||
free:
|
||||
tariff_id: 2
|
||||
start_date: <%= Date.today.to_s(:db) %>
|
||||
amount: 0
|
||||
flat_future:
|
||||
tariff_id: 1
|
||||
start_date: <%= Date.today.next.to_s(:db) %>
|
||||
amount: 100
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
class User < ActiveRecord::Base
|
||||
has_many :readings
|
||||
has_many :articles, :through => :readings
|
||||
has_many :comments, :as => :person
|
||||
has_many :hacks, :through => :comments, :source => :hack
|
||||
|
||||
def find_custom_articles
|
||||
articles.find(:all, :conditions => ["name = ?", "Article One"])
|
||||
end
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
santiago:
|
||||
id: 1
|
||||
name: Santiago
|
||||
drnic:
|
||||
id: 2
|
||||
name: Dr Nic
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue