Skip to content

Commit

Permalink
Merge branch 'master' of github.com:xui/xui into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
brianleroux committed Jan 11, 2011
2 parents 5068f61 + c5653d1 commit d8d47c4
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 145 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ To get the full source you need _Git_:
$ git submodule init
$ git submodule update

To build XUI, you will need _Ruby_:
To build XUI, you will need _Ruby_, and if minifying, _Java_ as well:

$ ./build # Generates lib/xui.js
$ ./build profile=bb # Builds XUI for BlackBerry 4/5 browsers (uses Sizzle selector engine)
$ ./build profile=ie # Builds XUI for Internet Explorer
$ ./build --minify # Builds XUI and minifies (_Java_ required)

Generating Documentation
------------------------
Expand Down
129 changes: 107 additions & 22 deletions build
Original file line number Diff line number Diff line change
@@ -1,53 +1,138 @@
#!/usr/bin/env ruby
require 'YAML'
require 'fileutils'

PROFILE_PATH = "util/profiles"

# TODO: print out build command line if no args provided.
# usage: ./build profile=whatever --minify

# man I sure love Windows! --alunny
is_windows = Dir.getwd[0,1] != "/"
echo_dot = is_windows ? "echo." : "echo"
mkdir = is_windows ? "mkdir" : "mkdir -p"
def show_usage
STDERR.puts "\nusage: ./build [ profile=<name> ] [ --minify ] [ --generate-docs ]"
STDERR.puts "\nsupported profiles are:"
Dir.chdir(PROFILE_PATH) do
STDERR.puts Dir['*.js'].map {|profile| "\t#{profile.sub(/\.js/, '')}"}
end
STDERR.puts "\nIf no profile is selected, 'core' will be used\n\n"
exit(1)
end

profile_matcher = /^profile=(.*)$/
profile_path = "util/profiles/"
# defaults
profile = "core"
minify = false
docs = false

$*.each do |arg|
minify = true if arg == "--minify"
docs = true if arg == "--doc"
profile = arg.match(profile_matcher)[1] if arg.match(profile_matcher)
ARGV.each do |arg|
case arg
when "--minify" then minify = true
when /^profile=(.*)$/ then profile = $1
when "--generate-docs" then docs = true
when "--help" then show_usage
else
STDERR.puts("Invalid parameter '#{arg}'") unless arg == "--help"
show_usage
end
end
hash = YAML.load_file "#{ profile_path }#{ profile }.js"
hash = YAML.load_file(File.join(PROFILE_PATH, profile) + ".js")

# clear previous file
`#{ mkdir } lib`
`#{ echo_dot } > #{ hash["out"] }`
target = hash["out"]
target_dir = File.dirname(target)

hash["include"].each do |include|
# a bit of overhead since not all files end in a newline
`cat #{ include }.js >> #{ hash["out"] }`
`#{ echo_dot } >> #{ hash["out"] }`
end
Dir.mkdir(target_dir) unless File.directory?(target_dir)
File.unlink(target) if File.exist?(target)

content = hash["include"].map {|library| File.read(library + ".js") }

File.open(target, "w") {|op| op.puts content }

if minify
puts "Minify-ing..."
minified_filename = hash['out'].sub(/\.js$/, '.min.js')
`java -jar util/compiler.jar --js=#{ hash["out"] } \
--js_output_file=#{ hash["out"] }.min`
--js_output_file=#{ minified_filename }`
end

if docs
XUI_DIR = File.expand_path(File.dirname(__FILE__))
DOC_DIR = File.join(XUI_DIR, 'doc')
SRC_DIR = File.join(XUI_DIR, 'src')

FileUtils.rm_r(DOC_DIR) if File.exists?(DOC_DIR)
FileUtils.mkdir(DOC_DIR)

FileUtils.cd(SRC_DIR) do
files = Dir['**/*.js'].reject{ |f| (f =~ /ie\//) != nil }.join(' ')
`jodoc --output ../doc #{files}`
end
end

# Generate HTML
puts "Generating documentation as HTML..."
generate_documentation(HTML_DIR)

# Generate EJS
puts "Generating documentation as EJS..."
generate_documentation(EJS_DIR)
html_to_ejs(EJS_DIR)
end

if docs
XUI_DIR = File.expand_path(File.dirname(__FILE__))
SRC_DIR = File.join(XUI_DIR, 'src')
DOC_DIR = File.join(XUI_DIR, 'doc')
HTML_DIR = File.join(DOC_DIR, 'html')
EJS_DIR = File.join(DOC_DIR, 'ejs')

def generate_documentation(output_directory)
output_directory = File.expand_path(output_directory)
FileUtils.mkdir_p(output_directory)

FileUtils.cd(SRC_DIR) do
files = Dir['**/*.js'].reject{ |f| (f =~ /ie\//) != nil }.join(' ')
`jodoc --title "XUI API Reference" --output #{output_directory} #{files}`
end
end

def html_to_ejs(directory)
FileUtils.cd(directory) do
rename = Hash.new

# Generate EJS filenames
Dir['**/*'].each do |filename|
# Remove prefix js_
# Remove prefix _
# Rename base to basics
# Remove .html and .js.html
# Add extension .ejs
rename[filename] = filename.sub(/^js_/, '') \
.sub(/^_/, '') \
.sub(/base\./, 'basics.') \
.sub(/\..*html/, '') \
.concat('.ejs')
end

# Rename each file
rename.each { |o, n| FileUtils.mv(o, n) }

# Alter file content
Dir['**/*'].each do |filename|
data = File.read(filename)

# Only save content of <body>
data.sub!(/.*<body>(.*)<\/body>.*/mi, "\\1")
# Update links to each filename
rename.each { |o, n| data.gsub!(o, File.basename(n, '.ejs')) }

File.open(filename, 'w') { |file| file.write(data) }
end
end
end

FileUtils.rm_r(DOC_DIR) if File.exists?(DOC_DIR)

# Generate HTML
generate_documentation(HTML_DIR)

# Generate EJS
generate_documentation(EJS_DIR)
html_to_ejs(EJS_DIR)
end
2 changes: 2 additions & 0 deletions spec/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ <h2 id="qunit-userAgent"></h2>
<ul id="html-list-test"></ul>
<div id="html-complex-test"></div>
<input type="checkbox" id="first-check" name="first-check" value="one" />
<div id="remove-me"></div>
<div id="remove-me-2"></div>
</div>

<div id="xhr_tests">
Expand Down
82 changes: 54 additions & 28 deletions spec/tests/core-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ CoreTests.prototype.run = function () {
test( '.not()', function(){
equals(x.not(".foo").length, 3, 'Should return number of elements after omitting a specific class as defined in markup');
});

// ---
/// dom.js specs
// ---

module("Selectors (base.js)", {
setup:function() {},
Expand Down Expand Up @@ -79,11 +75,11 @@ CoreTests.prototype.run = function () {
ok(style == 'rgb(0, 0, 255)' || style == '#0000ff', 'Should return proper style via CSS style name');
var styletwo = e.getStyle('backgroundColor').toLowerCase();
ok(styletwo == 'rgb(0, 0, 255)' || styletwo == '#0000ff', 'Should return proper style via DOM style name');
stop();
QUnit.stop();
e.getStyle('background-color', function(v){
v = v.toLowerCase();
ok(v == 'rgb(0, 0, 255)' || v == '#0000ff', 'Should return proper style in callback function');
start();
QUnit.start();
});
});
test( '.setStyle()', function(){
Expand Down Expand Up @@ -120,11 +116,11 @@ CoreTests.prototype.run = function () {

var z = x$('#style_tests').find('p');
var numFound = 0;
stop();
QUnit.stop();
z.hasClass('foo', function(el) {
numFound++;
ok(el.className.indexOf('foo') > -1, 'Callback function element parameter should always contain specified class');
if (numFound > 2) start();
if (numFound > 2) QUnit.start();
});
equals(numFound, x$('#style_tests').find('.foo').length, 'Should invoke callback function properly for every item with matching class');
});
Expand All @@ -146,11 +142,17 @@ CoreTests.prototype.run = function () {
}
});
test( 'Inserting html "after"', function() {
expect(2);
expect(5);
h.html('after', '<div>after</div>');
equals(h[0].nextSibling.innerHTML, 'after', 'New next sibling element should be created');
h.after('<div>after again</div>');
equals(h[0].nextSibling.innerHTML, 'after again', 'Using shortcut .after(), new next sibling element should be created');
equals(h[0].nextSibling.nextSibling.innerHTML, 'after', 'Doesn\'t destroy sibling nodes.');
var inputs = x$('input');
h.after(inputs);
equals(h[0].nextSibling, inputs[inputs.length-1], 'Using xui collection as parameter, next sibling to element is last element in parameter collection.');
h.after(inputs[0]);
equals(h[0].nextSibling, inputs[0], 'Using HTMLElement as parameter, next sibling to element is passed in element.');
});

test( 'Inserting html "before"', function() {
Expand Down Expand Up @@ -195,6 +197,21 @@ CoreTests.prototype.run = function () {
bottom.html('bottom', numerousItems);
//equals(bottom[0].childNodes.length, numOriginalElements + 3, 'Should append numerous elements when passed as string');
});
test( 'Removing html elements via "remove"', function() {
expect(2);
var el = x$('#remove-me');
el.remove();
equals(document.getElementById('remove-me'), null, 'Element should not exist after calling remove()');
var eltwo = x$('#remove-me-2');
eltwo.html('remove');
equals(document.getElementById('remove-me-2'), null, 'Element should not exist after calling html("remove")');
try {
x$('#doesnt-exist').remove();
x$('#neither-does-this-one').html('remove');
} catch(e) {
ok(false, 'Should not trigger exception on empty xui collections.');
}
});
test( '.html()', function(){
expect(4);
equals(h.html(), h[0].innerHTML, 'Should return innerHTML when called with no arguments');
Expand Down Expand Up @@ -240,13 +257,15 @@ CoreTests.prototype.run = function () {
x.xhr("helpers/example.html");
equals(x[0].innerHTML.toLowerCase(), '<h1>this is a html partial</h1>', 'Should insert partial into element');
});
asyncTest( 'Asynchronous XHRs', function() {

test( 'Asynchronous XHRs', function() {
QUnit.stop();
expect(2);
x.xhr("helpers/example.html", {
callback:function() {
ok(true, 'Specified callback function should be triggered properly');
equals(x[0].innerHTML,'','Defined callback should override default behaviour of injecting response into innerHTML');
start();
QUnit.start();
}
});
});
Expand All @@ -270,19 +289,20 @@ CoreTests.prototype.run = function () {
x = null;
}
});
asyncTest( '.tween()', function() {
test( '.tween()', function() {
QUnit.stop();
expect(2);
x.tween({left:'100px'}, function() {
ok(true, 'Callback should be called following tween');
equals(x[0].style.left,'100px', 'Tweened property should be set to final value as specified in tween call');
start();
QUnit.start();
});
});

// --
/// event specs
// --
module("Events", {
module("Events (event.js)", {
setup:function() {
// updated to create new element to reset events associated
var div = document.createElement('div');
Expand All @@ -294,38 +314,42 @@ CoreTests.prototype.run = function () {
x = null;
}
});
asyncTest('.on(event,function() { ... }) should bind anonymous function to selected element, and should be triggered by .fire(event) call', function () {
test('.on(event,function() { ... }) should bind anonymous function to selected element, and should be triggered by .fire(event) call', function () {
QUnit.stop();
expect(2);
x.on('click', function () {
ok(true, 'Click handler fired using fire("click") call');
this.innerHTML = 'firedclick';
equals(x[0].innerHTML, 'firedclick', 'Click handler function should have been able to modify innerHTML of element using "this" reference');
start();
QUnit.start();
}).fire('click').un('click');
});

asyncTest('.un(event) should unbind event handler from selected element', function () {
test('.un(event) should unbind event handler from selected element', function () {
QUnit.stop();
expect(0);
x.on('click', function () {
ok(false, 'Click handler should not be fired after calling .un(event)');
start();
QUnit.start();
}).un('click').fire('click');
start();
QUnit.start();
});

asyncTest('.on(event) should be able to bind a custom event', function () {
test('.on(event) should be able to bind a custom event', function () {
QUnit.stop();
expect(1);
x.on('brianisadonkey', function () {
ok(true, '"brianisadonkey" event handler should be called by .fire("brianisadonkey")');
start();
QUnit.start();
}).fire('brianisadonkey').un('brianisadonkey');
});

asyncTest('.un(event) doesn\'t interfere with other events registered on the element', function () {
test('.un(event) doesn\'t interfere with other events registered on the element', function () {
QUnit.stop();
expect(1);
x.on('custom', function () {
ok(true, '"custom" event handler should be called properly following "click" event unbinding and "custom" event firing');
start();
QUnit.start();
});
x.on('click', function () {
ok(false, '"click" event handler should not be called following "click" event unbinding and "custom" event firing');
Expand All @@ -342,15 +366,16 @@ CoreTests.prototype.run = function () {
equals(fired, 3, 'Counter should be incremented by three different event handlers');
});

asyncTest('Should be able to unbind specific events using .un(event, handler)', function () {
test('Should be able to unbind specific events using .un(event, handler)', function () {
QUnit.stop();
expect(1);
function one() {
ok(false, '.un(event, handler) should prevent function "handler" from being called');
start();
QUnit.start();
}
function two() {
ok(true, '.fire("click") should trigger the only registered event on element');
start();
QUnit.start();
}
x.on('click', one).on('click', two).un('click', one).fire('click');
});
Expand All @@ -366,7 +391,8 @@ CoreTests.prototype.run = function () {
equals(fired, 2);
});

asyncTest('Should be able to create bespoke events', function () {
test('Should be able to create bespoke events', function () {
QUnit.stop();
// note that teardown methods are needed - this is an early system
expect(1);

Expand All @@ -385,7 +411,7 @@ CoreTests.prototype.run = function () {
var fired = false;
x.on('tripleclick', function () {
ok(true, 'tripleclick bespoke event fired on element');
start();
QUnit.start();
}).fire('click').fire('click').fire('click');
});

Expand Down
Loading

0 comments on commit d8d47c4

Please sign in to comment.