gallerby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ .yardoc
19
+ doc
20
+ pkg
21
+
22
+ ## PROJECT::SPECIFIC
23
+ .sass-cache
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Waine Kerr
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ gallerby
2
+ ========
3
+
4
+ Think about a dead-simple static gallery generator, with nothing except pictures, thumbnails, previews. A kind of server directory listing for pictures. Enter Gallerby!
5
+
6
+ An example of a gallerby-generated gallery can be found [here]("http://wainekerr.github.com/gallerby").
7
+
8
+ ## Installation
9
+
10
+ Classic!
11
+
12
+ `(sudo) gem install gallerby`
13
+
14
+ ## Usage
15
+
16
+ Before building your gallery, you have to respect this kind of "directory model" :
17
+
18
+ name_of_my_gallery/ <---- This is where you gallery will reside.
19
+ originals/ <---- This is where you have to put your pictures.
20
+ thumbnails/ <---- This is where Gallerby will create thumbnails for you.
21
+ previews/ <---- This is where Gallerby will store "middle-sized" versions of your pictures for Lightbox.
22
+
23
+ When your directory is ready :
24
+
25
+ `gallerby -d directory_of_my_gallery`
26
+
27
+ Wait, and tada!
28
+
29
+ ## Moar Usage
30
+
31
+ If I was an asshole, i'd say you to RTFM. So :
32
+
33
+ $ gallerby -h
34
+ gallerby - frakin' dead simple gallery generator
35
+
36
+ Usage: gallerby -d [directory] [options]
37
+
38
+ Options are:
39
+ -d, --directory DIRECTORY Directory of the Gallery
40
+ -n, --name [NAME] Name (optional, default to directory)
41
+ -s, --summary [SUMMARY] Summary (optional, default empty)
42
+ -p, --per-page [PER_PAGE] Pictures to display per page (default is 20)
43
+ -h, --help RTFM, dude!
44
+
45
+ ## Updating
46
+
47
+ You can re-run `gallerby` to an existing gallery. It'll skip thumbnails & previews creation if files already exists.
48
+
49
+ Currently, no parameters are stored (like custom name, description, pictures per page). It's planned.
50
+
51
+ ## Copyright
52
+
53
+ Copyright (c) 2010 Waine Kerr.
54
+
55
+ Released under the terms of the MIT license, see LICENSE for details.
56
+
57
+ Please note that other software is included in gallerby and may be released under others licenses:
58
+
59
+ * [Prototype]("http://github.com/sstephenson/prototype"), Copyright (c) 2005-2010 Sam Stephenson
60
+ * [script.aculo.us]("http://github.com/madrobby/scriptaculous"), Copyright (c) 2005-2010 Thomas Fuchs
61
+ * [Lightbox]("http://huddletogether.com/projects/lightbox2"), by Lokesh Dhakar
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "gallerby"
8
+ gem.summary = %Q{Think about a webserver directory-listing for pictures.}
9
+ gem.description = %Q{Think about a dead-simple static gallery generator, with nothing except pictures, thumbnails, previews. A kind of server directory listing for pictures. Enter Gallerby!}
10
+ gem.email = "wk@heldscalla.org"
11
+ gem.homepage = "http://github.com/wainekerr/gallerby"
12
+ gem.authors = ["Waine Kerr"]
13
+ gem.executables = %w(gallerby)
14
+ gem.add_dependency "mini_magick", ">= 2.0.0"
15
+ gem.add_dependency "haml", ">= 3.0.17"
16
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
17
+ gem.add_development_dependency "yard", ">= 0"
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+ require 'rake/testtask'
25
+ Rake::TestTask.new(:test) do |test|
26
+ test.libs << 'lib' << 'test'
27
+ test.pattern = 'test/**/test_*.rb'
28
+ test.verbose = true
29
+ end
30
+
31
+ begin
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |test|
34
+ test.libs << 'test'
35
+ test.pattern = 'test/**/test_*.rb'
36
+ test.verbose = true
37
+ end
38
+ rescue LoadError
39
+ task :rcov do
40
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
+ end
42
+ end
43
+
44
+ task :test => :check_dependencies
45
+
46
+ task :default => :test
47
+
48
+ begin
49
+ require 'yard'
50
+ YARD::Rake::YardocTask.new
51
+ rescue LoadError
52
+ task :yardoc do
53
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
54
+ end
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/gallerby ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Runner for Gallerby
4
+
5
+ require 'ostruct'
6
+ require 'optparse'
7
+ require 'optparse/time'
8
+
9
+ lib_dir = File.dirname(__FILE__) + '/../lib/'
10
+ require File.dirname(__FILE__) + '/../lib/gallerby'
11
+
12
+ options = {:per_page=>20}
13
+
14
+ optparse = OptionParser.new do |opts|
15
+ opts.banner = <<BANNER
16
+ gallerby - frakin' dead simple gallery generator
17
+
18
+ Usage: #{File.basename($0)} -d [directory] [options]
19
+
20
+ Options are:
21
+ BANNER
22
+
23
+ opts.on_tail('-h', '--help', 'RTFM, dude!') do
24
+ puts opts
25
+ exit 1
26
+ end
27
+
28
+ opts.on('-d DIRECTORY', '--directory DIRECTORY', "Directory of the Gallery") do |f|
29
+ options[:directory] = f
30
+ end
31
+
32
+ opts.on('-n', '--name [NAME]', 'Name (optional, default to directory)') do |f|
33
+ options[:name] = f || options[:directory]
34
+ end
35
+
36
+ opts.on('-s', '--summary [SUMMARY]', 'Summary (optional, default empty)') do |f|
37
+ options[:summary] = f || ""
38
+ end
39
+
40
+ opts.on('-p', '--per-page [PER_PAGE]', Integer, 'Pictures to display per page (default is 20)') do |f|
41
+ options[:per_page] = f || 20
42
+ end
43
+ end
44
+
45
+ begin # From http://stackoverflow.com/questions/1541294/how-do-you-specify-a-required-switch-not-argument-with-ruby-optionparser/2149183#2149183
46
+ optparse.parse!
47
+ mandatory = [:directory]
48
+ missing = mandatory.select{ |param| options[param].nil? }
49
+ if not missing.empty?
50
+ puts optparse
51
+ exit 1
52
+ end
53
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
54
+ puts optparse
55
+ exit 1
56
+ end
57
+
58
+ begin
59
+ g = Gallerby.new(options[:directory], options[:per_page], options[:name], options[:summary])
60
+ g.verify_directory_structure
61
+ g.scan_pictures
62
+ puts "[WARNING ] Found 0 pictures in #{g.originals}. Your gallery will be empty!" if g.pictures.size == 0
63
+ g.map_pages
64
+ puts "[INFO ] Your gallery will have #{g.pictures.size} pictures in #{g.pages.size} pages."
65
+ print "[BUILDING] Thumbnails: " ; STDOUT.flush
66
+ g.build_thumbnails
67
+ print "[BUILDING] Previews: " ; STDOUT.flush
68
+ g.build_previews
69
+ puts "[INFO ] Copying assets and building CSS to #{g.directory}/assets"
70
+ g.copy_and_build_assets
71
+ print "[BUILDING] HTML: " ; STDOUT.flush
72
+ g.build_gallery
73
+ puts "[HOORAY ] Your gallery have been successfully builded. Enjoy \\o/"
74
+ rescue
75
+ puts "[OH NOES ] #{$!}"
76
+ exit 1
77
+ end
data/gallerby.gemspec ADDED
@@ -0,0 +1,82 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{gallerby}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Waine Kerr"]
12
+ s.date = %q{2010-08-22}
13
+ s.default_executable = %q{gallerby}
14
+ s.description = %q{Think about a dead-simple static gallery generator, with nothing except pictures, thumbnails, previews. A kind of server directory listing for pictures. Enter Gallerby!}
15
+ s.email = %q{wk@heldscalla.org}
16
+ s.executables = ["gallerby"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.md",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/gallerby",
29
+ "gallerby.gemspec",
30
+ "lib/gallerby.rb",
31
+ "lib/shared/assets/css/lightbox.css",
32
+ "lib/shared/assets/img/bullet.gif",
33
+ "lib/shared/assets/img/close.gif",
34
+ "lib/shared/assets/img/closelabel.gif",
35
+ "lib/shared/assets/img/donate-button.gif",
36
+ "lib/shared/assets/img/download-icon.gif",
37
+ "lib/shared/assets/img/loading.gif",
38
+ "lib/shared/assets/img/nextlabel.gif",
39
+ "lib/shared/assets/img/prevlabel.gif",
40
+ "lib/shared/assets/js/builder.js",
41
+ "lib/shared/assets/js/effects.js",
42
+ "lib/shared/assets/js/lightbox.js",
43
+ "lib/shared/assets/js/prototype.js",
44
+ "lib/shared/assets/js/scriptaculous.js",
45
+ "lib/shared/templates/gallerby.haml",
46
+ "lib/shared/templates/gallerby.sass",
47
+ "test/helper.rb",
48
+ "test/test_gallerby.rb"
49
+ ]
50
+ s.homepage = %q{http://github.com/wainekerr/gallerby}
51
+ s.rdoc_options = ["--charset=UTF-8"]
52
+ s.require_paths = ["lib"]
53
+ s.rubygems_version = %q{1.3.6}
54
+ s.summary = %q{Think about a webserver directory-listing for pictures.}
55
+ s.test_files = [
56
+ "test/helper.rb",
57
+ "test/test_gallerby.rb"
58
+ ]
59
+
60
+ if s.respond_to? :specification_version then
61
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
62
+ s.specification_version = 3
63
+
64
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
65
+ s.add_runtime_dependency(%q<mini_magick>, [">= 2.0.0"])
66
+ s.add_runtime_dependency(%q<haml>, [">= 3.0.17"])
67
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
68
+ s.add_development_dependency(%q<yard>, [">= 0"])
69
+ else
70
+ s.add_dependency(%q<mini_magick>, [">= 2.0.0"])
71
+ s.add_dependency(%q<haml>, [">= 3.0.17"])
72
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
73
+ s.add_dependency(%q<yard>, [">= 0"])
74
+ end
75
+ else
76
+ s.add_dependency(%q<mini_magick>, [">= 2.0.0"])
77
+ s.add_dependency(%q<haml>, [">= 3.0.17"])
78
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
79
+ s.add_dependency(%q<yard>, [">= 0"])
80
+ end
81
+ end
82
+
data/lib/gallerby.rb ADDED
@@ -0,0 +1,139 @@
1
+ %w{fileutils mini_magick haml sass}.each {|r| require r }
2
+
3
+ class Gallerby
4
+ PICTURES_MATCHER = "*.{jpg,jpeg,JPG,JPEG,gif,GIF,png,PNG}"
5
+ SHARED_PATH = File.expand_path('../shared', __FILE__)
6
+ HAML_OPTS = {:format => :html5, :escape_html => true}
7
+ SASS_OPTS = {}
8
+ attr_accessor :directory, :name, :pictures, :originals, :pages, :description, :pages_links
9
+
10
+ # Well... initialize the Gallerby.
11
+ #
12
+ # @param [String] directory string of the gallery root directory
13
+ # @param [optional, Integer] per_page number of pictures to display per page
14
+ # @param [optional, String] name custom name for the gallery (default is the directory)
15
+ # @param [optional, String] description description for the gallery (default is nothing)
16
+ # @raise [RuntimeError] if gallery directory don't exists or don't match the required structure.
17
+ def initialize(directory, per_page=20, name=nil, description=nil)
18
+ @directory, @per_page, @name, @description = directory, per_page, name, description
19
+ @thumbs, @previews, @originals = "#{@directory}/thumbnails", "#{@directory}/previews", "#{@directory}/originals"
20
+ raise "Directory #{@directory} don't exists." unless File.exists?(@directory)
21
+ end
22
+
23
+ # Verify if the directory structure match the gallerby requirements. See the README for more information
24
+ #
25
+ # @return [TrueClass, FalseClass]
26
+ def verify_directory_structure
27
+ raise "Thumbnails directory (#{@thumbs}) don't exist." unless File.exists?(@thumbs)
28
+ raise "Previews directory (#{@previews}) don't exist." unless File.exists?(@previews)
29
+ raise "Originals directory (#{@originals}) don't exist." unless File.exists?(@originals)
30
+ end
31
+
32
+ # Scan for pictures in the original directory.
33
+ # @returns [Array] Filenames of the pictures
34
+ def scan_pictures
35
+ @pictures = Dir["#{@originals}/#{PICTURES_MATCHER}"]
36
+ end
37
+
38
+ # Map pages/pictures for pagination purposes
39
+ #
40
+ # @returns [Hash] Pages ID & Pictures associated to the page.
41
+ def map_pages
42
+ @pages = {}
43
+ page_id = 0
44
+ pict_count = 0
45
+ page_pictures = []
46
+
47
+ @pictures.each do |picture|
48
+ if pict_count == @per_page
49
+ @pages[page_id] = page_pictures
50
+ page_pictures = []
51
+ page_id += 1
52
+ pict_count = 0
53
+ end
54
+ page_pictures << picture
55
+ pict_count += 1
56
+ end
57
+
58
+ @pages
59
+ end
60
+
61
+ # Build the thumbnails
62
+ #
63
+ # @see Gallerby#the_rezise_machine
64
+ def build_thumbnails(size="200x200", verbose=true)
65
+ the_resize_machine(@pictures, @thumbs, size, verbose)
66
+ end
67
+
68
+ # Build the previews
69
+ #
70
+ # @see Gallerby#the_rezise_machine
71
+ def build_previews(size="900x780", verbose=true)
72
+ the_resize_machine(@pictures, @previews, size, verbose)
73
+ end
74
+
75
+ # Copy the assets (JS, CSS and images) to the gallery directory, and build the CSS.
76
+ def copy_and_build_assets
77
+ FileUtils.cp_r("#{SHARED_PATH}/assets", @directory)
78
+ sass = Sass::Engine.new(File.read("#{SHARED_PATH}/templates/gallerby.sass"), SASS_OPTS).to_css
79
+ File.open("#{@directory}/assets/css/gallerby.css", 'w') {|f| f.write(sass) }
80
+ end
81
+
82
+ # Build all HTML pages of the gallery.
83
+ #
84
+ # @see Gallerby#build_page
85
+ def build_gallery(verbose=true)
86
+ @pages_links = {}
87
+ @pages.each do |page_id,pictures|
88
+ page_name = page_id==0 ? "index" : "page#{page_id}"
89
+ build_page(page_id, page_name, pictures)
90
+ (print "." ; STDOUT.flush) if verbose
91
+ end
92
+ (print " OK!\n" ; STDOUT.flush) if verbose
93
+ end
94
+
95
+ # Helper to build the navigations links
96
+ def navigation_links(current_page)
97
+ links = "Pages:&nbsp;"
98
+ @pages.keys.sort.each do |pid|
99
+ page_link = pid==0 ? "index.html" : "page#{pid}.html"
100
+ extra_html = pid==current_page ? " class='selected'" : ""
101
+ links << "<a href='#{page_link}' title='Page #{pid+1}'#{extra_html}>#{pid+1}</a>&nbsp;"
102
+ end
103
+ links
104
+ end
105
+
106
+ private
107
+ # Build a page of the gallery.
108
+ #
109
+ # @params [Integer] pid ID of the page
110
+ # @params [String] pname Name of the page (index or pageID)
111
+ # @picts [Array] Array of pictures path
112
+ def build_page(pid, pname, picts)
113
+ page_pictures = []
114
+ picts.each {|pict| page_pictures << pict.gsub("#{@originals}/", '') }
115
+ locals = {:gallery => self, :pid => pid, :pname => pname, :pictures => page_pictures}
116
+ haml = Haml::Engine.new(File.read("#{SHARED_PATH}/templates/gallerby.haml"), HAML_OPTS).render(Object.new, locals)
117
+ File.open("#{@directory}/#{pname}.html", 'w') {|f| f.write(haml) }
118
+ end
119
+
120
+ # Resize an Array of pictures
121
+ #
122
+ # @params [Array] pictures Array of pictures path
123
+ # @params [String] save_path in which directory to save the picture
124
+ # @params [String] size Size to use for rezising.
125
+ # @params [Boolean] verbose Enable verbose or not (useful for `gallerby` binary)
126
+ def the_resize_machine(pictures, save_path, size, verbose)
127
+ pictures.each do |picture|
128
+ read_from = "#{picture}"
129
+ write_to = "#{save_path}#{picture.gsub(@originals, '')}"
130
+ unless File.exists?(write_to)
131
+ magick = MiniMagick::Image.from_file(read_from)
132
+ magick.resize(size)
133
+ magick.write(write_to)
134
+ (print "." ; STDOUT.flush) if verbose
135
+ end
136
+ end
137
+ (print " OK!\n" ; STDOUT.flush) if verbose
138
+ end
139
+ end
@@ -0,0 +1,27 @@
1
+ #lightbox{ position: absolute; left: 0; width: 100%; z-index: 100; text-align: center; line-height: 0;}
2
+ #lightbox img{ width: auto; height: auto;}
3
+ #lightbox a img{ border: none; }
4
+
5
+ #outerImageContainer{ position: relative; background-color: #fff; width: 250px; height: 250px; margin: 0 auto; }
6
+ #imageContainer{ padding: 10px; }
7
+
8
+ #loading{ position: absolute; top: 40%; left: 0%; height: 25%; width: 100%; text-align: center; line-height: 0; }
9
+ #hoverNav{ position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 10; }
10
+ #imageContainer>#hoverNav{ left: 0;}
11
+ #hoverNav a{ outline: none;}
12
+
13
+ #prevLink, #nextLink{ width: 49%; height: 100%; background-image: url(data:image/gif;base64,AAAA); /* Trick IE into showing hover */ display: block; }
14
+ #prevLink { left: 0; float: left;}
15
+ #nextLink { right: 0; float: right;}
16
+ #prevLink:hover, #prevLink:visited:hover { background: url(../img/prevlabel.gif) left 15% no-repeat; }
17
+ #nextLink:hover, #nextLink:visited:hover { background: url(../img/nextlabel.gif) right 15% no-repeat; }
18
+
19
+ #imageDataContainer{ font: 10px Verdana, Helvetica, sans-serif; background-color: #fff; margin: 0 auto; line-height: 1.4em; overflow: auto; width: 100% ; }
20
+
21
+ #imageData{ padding:0 10px; color: #666; }
22
+ #imageData #imageDetails{ width: 70%; float: left; text-align: left; }
23
+ #imageData #caption{ font-weight: bold; }
24
+ #imageData #numberDisplay{ display: block; clear: left; padding-bottom: 1.0em; }
25
+ #imageData #bottomNavClose{ width: 66px; float: right; padding-bottom: 0.7em; outline: none;}
26
+
27
+ #overlay{ position: absolute; top: 0; left: 0; z-index: 90; width: 100%; height: 500px; background-color: #000; }
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,136 @@
1
+ // script.aculo.us builder.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
2
+
3
+ // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
+ //
5
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
6
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
7
+
8
+ var Builder = {
9
+ NODEMAP: {
10
+ AREA: 'map',
11
+ CAPTION: 'table',
12
+ COL: 'table',
13
+ COLGROUP: 'table',
14
+ LEGEND: 'fieldset',
15
+ OPTGROUP: 'select',
16
+ OPTION: 'select',
17
+ PARAM: 'object',
18
+ TBODY: 'table',
19
+ TD: 'table',
20
+ TFOOT: 'table',
21
+ TH: 'table',
22
+ THEAD: 'table',
23
+ TR: 'table'
24
+ },
25
+ // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
26
+ // due to a Firefox bug
27
+ node: function(elementName) {
28
+ elementName = elementName.toUpperCase();
29
+
30
+ // try innerHTML approach
31
+ var parentTag = this.NODEMAP[elementName] || 'div';
32
+ var parentElement = document.createElement(parentTag);
33
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
34
+ parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
35
+ } catch(e) {}
36
+ var element = parentElement.firstChild || null;
37
+
38
+ // see if browser added wrapping tags
39
+ if(element && (element.tagName.toUpperCase() != elementName))
40
+ element = element.getElementsByTagName(elementName)[0];
41
+
42
+ // fallback to createElement approach
43
+ if(!element) element = document.createElement(elementName);
44
+
45
+ // abort if nothing could be created
46
+ if(!element) return;
47
+
48
+ // attributes (or text)
49
+ if(arguments[1])
50
+ if(this._isStringOrNumber(arguments[1]) ||
51
+ (arguments[1] instanceof Array) ||
52
+ arguments[1].tagName) {
53
+ this._children(element, arguments[1]);
54
+ } else {
55
+ var attrs = this._attributes(arguments[1]);
56
+ if(attrs.length) {
57
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
58
+ parentElement.innerHTML = "<" +elementName + " " +
59
+ attrs + "></" + elementName + ">";
60
+ } catch(e) {}
61
+ element = parentElement.firstChild || null;
62
+ // workaround firefox 1.0.X bug
63
+ if(!element) {
64
+ element = document.createElement(elementName);
65
+ for(attr in arguments[1])
66
+ element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
67
+ }
68
+ if(element.tagName.toUpperCase() != elementName)
69
+ element = parentElement.getElementsByTagName(elementName)[0];
70
+ }
71
+ }
72
+
73
+ // text, or array of children
74
+ if(arguments[2])
75
+ this._children(element, arguments[2]);
76
+
77
+ return element;
78
+ },
79
+ _text: function(text) {
80
+ return document.createTextNode(text);
81
+ },
82
+
83
+ ATTR_MAP: {
84
+ 'className': 'class',
85
+ 'htmlFor': 'for'
86
+ },
87
+
88
+ _attributes: function(attributes) {
89
+ var attrs = [];
90
+ for(attribute in attributes)
91
+ attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
92
+ '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
93
+ return attrs.join(" ");
94
+ },
95
+ _children: function(element, children) {
96
+ if(children.tagName) {
97
+ element.appendChild(children);
98
+ return;
99
+ }
100
+ if(typeof children=='object') { // array can hold nodes and text
101
+ children.flatten().each( function(e) {
102
+ if(typeof e=='object')
103
+ element.appendChild(e)
104
+ else
105
+ if(Builder._isStringOrNumber(e))
106
+ element.appendChild(Builder._text(e));
107
+ });
108
+ } else
109
+ if(Builder._isStringOrNumber(children))
110
+ element.appendChild(Builder._text(children));
111
+ },
112
+ _isStringOrNumber: function(param) {
113
+ return(typeof param=='string' || typeof param=='number');
114
+ },
115
+ build: function(html) {
116
+ var element = this.node('div');
117
+ $(element).update(html.strip());
118
+ return element.down();
119
+ },
120
+ dump: function(scope) {
121
+ if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
122
+
123
+ var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
124
+ "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
125
+ "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
126
+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
127
+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
128
+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
129
+
130
+ tags.each( function(tag){
131
+ scope[tag] = function() {
132
+ return Builder.node.apply(Builder, [tag].concat($A(arguments)));
133
+ }
134
+ });
135
+ }
136
+ }