topfunky-castanaut 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Copyright.txt +29 -0
- data/History.txt +9 -0
- data/Manifest.txt +31 -0
- data/README.txt +161 -0
- data/Rakefile +19 -0
- data/bin/castanaut +7 -0
- data/cbin/osxautomation +0 -0
- data/lib/castanaut.rb +64 -0
- data/lib/castanaut/exceptions.rb +32 -0
- data/lib/castanaut/keys.rb +43 -0
- data/lib/castanaut/main.rb +20 -0
- data/lib/castanaut/movie.rb +428 -0
- data/lib/castanaut/plugin.rb +26 -0
- data/lib/plugins/ishowu.rb +94 -0
- data/lib/plugins/mousepose.rb +38 -0
- data/lib/plugins/safari.rb +124 -0
- data/lib/plugins/textmate.rb +39 -0
- data/scripts/coords.js +48 -0
- data/scripts/gebys.js +612 -0
- data/spec/castanaut_spec.rb +9 -0
- data/spec/spec_helper.rb +18 -0
- data/tasks/ann.rake +77 -0
- data/tasks/annotations.rake +22 -0
- data/tasks/doc.rake +49 -0
- data/tasks/gem.rake +110 -0
- data/tasks/manifest.rake +50 -0
- data/tasks/post_load.rake +18 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +221 -0
- data/tasks/spec.rake +43 -0
- data/tasks/svn.rake +44 -0
- metadata +96 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module Castanaut
|
2
|
+
|
3
|
+
# Castanaut uses plugins to extend the available actions beyond simple
|
4
|
+
# mouse and keyboard input. Typically each plugin is application-specific.
|
5
|
+
# See the Safari, Mousepose and Ishowu plugins for examples, and review the
|
6
|
+
# README.txt for details on creating your own.
|
7
|
+
#
|
8
|
+
# In short, for a plugin called "foo", your script should have this structure:
|
9
|
+
#
|
10
|
+
# module Castanaut
|
11
|
+
# module Plugin
|
12
|
+
# module Foo
|
13
|
+
#
|
14
|
+
# # define your stage directions (ie, Movie instance methods) here.
|
15
|
+
#
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# The script must exist in a sub-directory of the screenplay's location
|
21
|
+
# called "plugins", and must be called (in this case): foo.rb.
|
22
|
+
#
|
23
|
+
module Plugin
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Castanaut; module Plugin
|
2
|
+
|
3
|
+
# This module provides primitive support for iShowU, a screencast capturing
|
4
|
+
# tool for Mac OS X from Shiny White Box.
|
5
|
+
#
|
6
|
+
# iShowU is widely considered a good, simple application for its purpose,
|
7
|
+
# but you're by no means required to use it for Castanaut. Simply write
|
8
|
+
# your own module for Snapz Pro, or ScreenFlow, or whatever you like.
|
9
|
+
#
|
10
|
+
# Shiny White Box is promising much better Applescript support in an
|
11
|
+
# imminent version, which could tidy up this module quite a bit.
|
12
|
+
#
|
13
|
+
# More info: http://www.shinywhitebox.com/home/home.html
|
14
|
+
module Ishowu
|
15
|
+
|
16
|
+
# Set the screencast to capture a particular region of the screen.
|
17
|
+
# Generate appropriately-formatted co-ordinates using Castanaut::Movie#to.
|
18
|
+
def ishowu_set_region(*options)
|
19
|
+
ishowu_applescriptify
|
20
|
+
|
21
|
+
options = combine_options(*options)
|
22
|
+
|
23
|
+
ishowu_menu_item("Capture", "Capture full screen")
|
24
|
+
sleep(0.2)
|
25
|
+
ishowu_menu_item("Capture", "Capture custom area", false)
|
26
|
+
sleep(0.2)
|
27
|
+
automatically "mousewarp 4 4"
|
28
|
+
|
29
|
+
drag to(options[:to][:left], options[:to][:top])
|
30
|
+
|
31
|
+
sleep(0.2)
|
32
|
+
bounds = screen_size
|
33
|
+
automatically "mousewarp #{bounds[:to][:width]} #{bounds[:to][:height]}"
|
34
|
+
drag to(
|
35
|
+
options[:to][:left] + options[:to][:width],
|
36
|
+
options[:to][:top] + options[:to][:height]
|
37
|
+
)
|
38
|
+
hit Enter
|
39
|
+
ishowu_hide
|
40
|
+
end
|
41
|
+
|
42
|
+
# Tell iShowU to start recording. Will automatically stop recording when
|
43
|
+
# the movie is ended, unless you set :auto_stop => false in options.
|
44
|
+
def ishowu_start_recording(options = {})
|
45
|
+
ishowu_hide
|
46
|
+
ishowu_menu_item("Capture", "Start capture")
|
47
|
+
unless options[:auto_stop] == false
|
48
|
+
at_end_of_movie { ishowu_stop_recording }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Tell iShowU to stop recording.
|
53
|
+
def ishowu_stop_recording
|
54
|
+
ishowu_menu_item("Capture", "Stop capture")
|
55
|
+
end
|
56
|
+
|
57
|
+
# Execute an iShowU menu option.
|
58
|
+
def ishowu_menu_item(menu, item, quiet = true)
|
59
|
+
ascript = %Q`
|
60
|
+
tell application "iShowU"
|
61
|
+
activate
|
62
|
+
tell application "System Events"
|
63
|
+
click menu item "#{item}" of menu "#{menu}" of menu bar item "#{menu}" of menu bar 1 of process "iShowU"
|
64
|
+
#{'set visible of process "iShowU" to false' if quiet}
|
65
|
+
end tell
|
66
|
+
end
|
67
|
+
`
|
68
|
+
execute_applescript(ascript)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Hide the iShowU window. This is a bit random, and suggestions are
|
72
|
+
# welcomed.
|
73
|
+
def ishowu_hide
|
74
|
+
ishowu_menu_item("iShowU", "Hide iShowU")
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
# iShowU is not Applescript-enabled out of the box. This fix, arguably
|
79
|
+
# a hack, lets us do some limited work with it in Applescript.
|
80
|
+
def ishowu_applescriptify
|
81
|
+
execute_applescript(%Q`
|
82
|
+
try
|
83
|
+
tell application "Finder"
|
84
|
+
set the a_app to (application file id "com.tcdc.Digitizer") as alias
|
85
|
+
end tell
|
86
|
+
set the plist_filepath to the quoted form of ¬
|
87
|
+
((POSIX path of the a_app) & "Contents/Info")
|
88
|
+
do shell script "defaults write " & the plist_filepath & space ¬
|
89
|
+
& "NSAppleScriptEnabled -bool YES"
|
90
|
+
end try
|
91
|
+
`)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end; end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Castanaut; module Plugin
|
2
|
+
|
3
|
+
# This module provides actions for controlling Mousepose, a commercial
|
4
|
+
# application from Boinx Software. Basically it lets you put a halo around
|
5
|
+
# the mouse whenever a key mouse action occurs.
|
6
|
+
#
|
7
|
+
# It doesn't do any configuration of Mousepose on the fly. Configure
|
8
|
+
# Mousepose settings before running your screenplay.
|
9
|
+
#
|
10
|
+
# Tested against Mousepose 2. More info: http://www.boinx.com/mousepose
|
11
|
+
module Mousepose
|
12
|
+
|
13
|
+
# Put a halo around the mouse. If a block is given to this method,
|
14
|
+
# the halo will be turned off when the block completes. Otherwise,
|
15
|
+
# you'll have to use dim to dismiss the halo.
|
16
|
+
def highlight
|
17
|
+
execute_applescript(%Q`
|
18
|
+
tell application "Mousepose"
|
19
|
+
start effect
|
20
|
+
end
|
21
|
+
`)
|
22
|
+
if block_given?
|
23
|
+
yield
|
24
|
+
dim
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Dismiss the halo around the mouse that was invoked by a previous
|
29
|
+
# highlight method.
|
30
|
+
def dim
|
31
|
+
execute_applescript(%Q`
|
32
|
+
tell application "Mousepose"
|
33
|
+
stop effect
|
34
|
+
end
|
35
|
+
`)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end; end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Castanaut
|
2
|
+
|
3
|
+
module Plugin
|
4
|
+
# This module provides actions for controlling Safari. It's tested against
|
5
|
+
# Safari 3 on Mac OS X 10.5.2.
|
6
|
+
module Safari
|
7
|
+
|
8
|
+
# Open a URL in the front Safari tab.
|
9
|
+
def url(str)
|
10
|
+
execute_applescript(%Q`
|
11
|
+
tell application "safari"
|
12
|
+
do JavaScript "location.href = '#{str}'" in front document
|
13
|
+
end tell
|
14
|
+
`)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get the co-ordinates of an element in the front Safari tab. Use this
|
18
|
+
# with Castanaut::Movie#cursor to send the mouse cursor to the element.
|
19
|
+
#
|
20
|
+
# Options include:
|
21
|
+
# * :index - an integer (*n*) that gets the *n*th element matching the
|
22
|
+
# selector. Defaults to the first element.
|
23
|
+
# * :area - whereabouts in the element do you want the coordinates.
|
24
|
+
# Valid values are: left, center, right, and top, middle, bottom.
|
25
|
+
# Defaults to ["center", "middle"].
|
26
|
+
# If single axis is given (eg "left"), the other axis uses its default.
|
27
|
+
def to_element(selector, options = {})
|
28
|
+
pos = options.delete(:area)
|
29
|
+
coords = element_coordinates(selector, options)
|
30
|
+
|
31
|
+
x_axis, y_axis = [:center, :middle]
|
32
|
+
[pos].flatten.first(2).each do |p|
|
33
|
+
p = p.to_s.downcase
|
34
|
+
x_axis = p.to_sym if %w[left center right].include?(p)
|
35
|
+
y_axis = p.to_sym if %w[top middle bottom].include?(p)
|
36
|
+
end
|
37
|
+
|
38
|
+
edge_offset = options[:edge_offset] || 3
|
39
|
+
case x_axis
|
40
|
+
when :left
|
41
|
+
x = coords[0] + edge_offset
|
42
|
+
when :center
|
43
|
+
x = (coords[0] + coords[2] * 0.5).to_i
|
44
|
+
when :right
|
45
|
+
x = (coords[0] + coords[2]) - edge_offset
|
46
|
+
end
|
47
|
+
|
48
|
+
case y_axis
|
49
|
+
when :top
|
50
|
+
y = coords[1] + edge_offset
|
51
|
+
when :middle
|
52
|
+
y = (coords[1] + coords[3] * 0.5).to_i
|
53
|
+
when :bottom
|
54
|
+
y = (coords[1] + coords[3]) - edge_offset
|
55
|
+
end
|
56
|
+
|
57
|
+
result = { :to => { :left => x, :top => y } }
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
# Note: the script should set the Castanaut.result variable.
|
62
|
+
def execute_javascript(scpt)
|
63
|
+
execute_applescript %Q`
|
64
|
+
tell application "Safari"
|
65
|
+
do JavaScript "
|
66
|
+
document.oldTitle = document.title;
|
67
|
+
#{escape_dq(scpt)}
|
68
|
+
if (typeof Castanaut.result != 'undefined') {
|
69
|
+
document.title = Castanaut.result;
|
70
|
+
}
|
71
|
+
" in front document
|
72
|
+
set the_result to ((name of window 1) as string)
|
73
|
+
do JavaScript "
|
74
|
+
document.title = document.oldTitle;
|
75
|
+
" in front document
|
76
|
+
return the_result
|
77
|
+
end tell
|
78
|
+
`
|
79
|
+
end
|
80
|
+
|
81
|
+
def element_coordinates(selector, options = {})
|
82
|
+
index = options[:index] || 0
|
83
|
+
gebys = script('gebys.js')
|
84
|
+
cjs = script('coords.js')
|
85
|
+
coords = execute_javascript(%Q`
|
86
|
+
#{gebys}
|
87
|
+
#{cjs}
|
88
|
+
Castanaut.result = Castanaut.Coords.forElement(
|
89
|
+
'#{selector}',
|
90
|
+
#{index}
|
91
|
+
);
|
92
|
+
`)
|
93
|
+
|
94
|
+
unless coords.match(/\d+ \d+ \d+ \d+/)
|
95
|
+
raise Castanaut::Exceptions::ElementNotFound
|
96
|
+
end
|
97
|
+
|
98
|
+
coords = coords.split(' ').collect {|c| c.to_i}
|
99
|
+
|
100
|
+
if coords.any? {|c| c < 0 }
|
101
|
+
raise Castanaut::Exceptions::ElementOffScreen
|
102
|
+
end
|
103
|
+
|
104
|
+
coords
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
module Exceptions
|
111
|
+
# When getting an element's coordinates, this is raised if no element on
|
112
|
+
# the page matches the selector given.
|
113
|
+
class ElementNotFound < CastanautError
|
114
|
+
end
|
115
|
+
|
116
|
+
# When getting an element's coordinates, this is raised if the element
|
117
|
+
# is found, but cannot be shown on the screen. Normally, we automatically
|
118
|
+
# scroll to an element that is currently off-screen, but sometimes that
|
119
|
+
# might not be possible (such as if the element is display: none).
|
120
|
+
class ElementOffScreen < CastanautError
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Castanaut; module Plugin
|
2
|
+
|
3
|
+
##
|
4
|
+
# Contributed by Geoffrey Grosenbach
|
5
|
+
# http://peepcode.com
|
6
|
+
|
7
|
+
module Textmate
|
8
|
+
|
9
|
+
##
|
10
|
+
# Types text into TextMate all at once.
|
11
|
+
#
|
12
|
+
# The as_snippet option is documented but doesn't seem to do anything.
|
13
|
+
|
14
|
+
def tm_insert_text(text, as_snippet=false)
|
15
|
+
escaped_text = text.gsub(/"/, '\"')
|
16
|
+
snippet_directive = (as_snippet ? "with as snippet" : "")
|
17
|
+
|
18
|
+
execute_applescript(%Q`
|
19
|
+
tell application "TextMate"
|
20
|
+
insert "#{escaped_text}" #{snippet_directive}
|
21
|
+
end
|
22
|
+
`)
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Open a file, optionally at a specific line and column.
|
27
|
+
|
28
|
+
def tm_get_url(file_path, line=0, column=0)
|
29
|
+
full_url = "txmt://open?url=file://#{file_path}&line=#{line}&column=#{column}"
|
30
|
+
execute_applescript(%Q`
|
31
|
+
tell application "TextMate"
|
32
|
+
get url "#{full_url}"
|
33
|
+
end
|
34
|
+
`)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end; end
|
data/scripts/coords.js
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
var Castanaut = Castanaut || {};
|
2
|
+
|
3
|
+
Castanaut.Coords = Castanaut.Coords || {
|
4
|
+
documentPos: function (obj) {
|
5
|
+
origObj = obj;
|
6
|
+
var curleft = curtop = 0;
|
7
|
+
if (obj.offsetParent) {
|
8
|
+
do {
|
9
|
+
curleft += obj.offsetLeft;
|
10
|
+
curtop += obj.offsetTop;
|
11
|
+
} while (obj = obj.offsetParent);
|
12
|
+
}
|
13
|
+
return [curleft,curtop,origObj.offsetWidth,origObj.offsetHeight];
|
14
|
+
},
|
15
|
+
|
16
|
+
windowPos: function (obj) {
|
17
|
+
var pos = Castanaut.Coords.documentPos(obj);
|
18
|
+
pos[0] -= window.scrollX;
|
19
|
+
pos[1] -= window.scrollY;
|
20
|
+
if (pos[0] > window.innerWidth || pos[0] < 0) {
|
21
|
+
pos[0] = -1;
|
22
|
+
}
|
23
|
+
if (pos[1] > window.innerHeight || pos[1] < 0) {
|
24
|
+
pos[1] = -1;
|
25
|
+
}
|
26
|
+
return pos;
|
27
|
+
},
|
28
|
+
|
29
|
+
forElement: function (selector, index) {
|
30
|
+
var obj = Castanaut.DomQuery.select(selector)[index];
|
31
|
+
var pos = Castanaut.Coords.windowPos(obj);
|
32
|
+
if (pos[0] < 0 || pos[1] < 0) {
|
33
|
+
obj.scrollIntoView();
|
34
|
+
pos = Castanaut.Coords.windowPos(obj);
|
35
|
+
if (pos[0] < 0 || pos[1] < 0) {
|
36
|
+
return pos.join(' ');
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
pos[0] += window.screenX + (window.outerWidth - window.innerWidth);
|
41
|
+
|
42
|
+
pos[1] += window.screenY + (window.outerHeight - window.innerHeight);
|
43
|
+
if (window.statusbar.visible) {
|
44
|
+
pos[1] -= 14;
|
45
|
+
}
|
46
|
+
return pos.join(' ');
|
47
|
+
}
|
48
|
+
}
|
data/scripts/gebys.js
ADDED
@@ -0,0 +1,612 @@
|
|
1
|
+
// NB: this is actually a slightly modified form of the Ext JS implementation,
|
2
|
+
// re-namespaced to avoid conflicts. (See also Copyright.txt.)
|
3
|
+
var Castanaut = Castanaut || {};
|
4
|
+
Castanaut.DomQuery = Castanaut.DomQuery || function(){
|
5
|
+
var cache = {}, simpleCache = {}, valueCache = {};
|
6
|
+
var nonSpace = /\S/;
|
7
|
+
var trimRe = /^\s+|\s+$/g;
|
8
|
+
var tplRe = /\{(\d+)\}/g;
|
9
|
+
var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
|
10
|
+
var tagTokenRe = /^(#)?([\w-\*]+)/;
|
11
|
+
var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
|
12
|
+
|
13
|
+
function child(p, index){
|
14
|
+
var i = 0;
|
15
|
+
var n = p.firstChild;
|
16
|
+
while(n){
|
17
|
+
if(n.nodeType == 1){
|
18
|
+
if(++i == index){
|
19
|
+
return n;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
n = n.nextSibling;
|
23
|
+
}
|
24
|
+
return null;
|
25
|
+
};
|
26
|
+
|
27
|
+
function next(n){
|
28
|
+
while((n = n.nextSibling) && n.nodeType != 1);
|
29
|
+
return n;
|
30
|
+
};
|
31
|
+
|
32
|
+
function prev(n){
|
33
|
+
while((n = n.previousSibling) && n.nodeType != 1);
|
34
|
+
return n;
|
35
|
+
};
|
36
|
+
|
37
|
+
function children(d){
|
38
|
+
var n = d.firstChild, ni = -1;
|
39
|
+
while(n){
|
40
|
+
var nx = n.nextSibling;
|
41
|
+
if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
|
42
|
+
d.removeChild(n);
|
43
|
+
}else{
|
44
|
+
n.nodeIndex = ++ni;
|
45
|
+
}
|
46
|
+
n = nx;
|
47
|
+
}
|
48
|
+
return this;
|
49
|
+
};
|
50
|
+
|
51
|
+
function byClassName(c, a, v){
|
52
|
+
if(!v){
|
53
|
+
return c;
|
54
|
+
}
|
55
|
+
var r = [], ri = -1, cn;
|
56
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
57
|
+
if((' '+ci.className+' ').indexOf(v) != -1){
|
58
|
+
r[++ri] = ci;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
return r;
|
62
|
+
};
|
63
|
+
|
64
|
+
function attrValue(n, attr){
|
65
|
+
if(!n.tagName && typeof n.length != "undefined"){
|
66
|
+
n = n[0];
|
67
|
+
}
|
68
|
+
if(!n){
|
69
|
+
return null;
|
70
|
+
}
|
71
|
+
if(attr == "for"){
|
72
|
+
return n.htmlFor;
|
73
|
+
}
|
74
|
+
if(attr == "class" || attr == "className"){
|
75
|
+
return n.className;
|
76
|
+
}
|
77
|
+
return n.getAttribute(attr) || n[attr];
|
78
|
+
|
79
|
+
};
|
80
|
+
|
81
|
+
function getNodes(ns, mode, tagName){
|
82
|
+
var result = [], ri = -1, cs;
|
83
|
+
if(!ns){
|
84
|
+
return result;
|
85
|
+
}
|
86
|
+
tagName = tagName || "*";
|
87
|
+
if(typeof ns.getElementsByTagName != "undefined"){
|
88
|
+
ns = [ns];
|
89
|
+
}
|
90
|
+
if(!mode){
|
91
|
+
for(var i = 0, ni; ni = ns[i]; i++){
|
92
|
+
cs = ni.getElementsByTagName(tagName);
|
93
|
+
for(var j = 0, ci; ci = cs[j]; j++){
|
94
|
+
result[++ri] = ci;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}else if(mode == "/" || mode == ">"){
|
98
|
+
var utag = tagName.toUpperCase();
|
99
|
+
for(var i = 0, ni, cn; ni = ns[i]; i++){
|
100
|
+
cn = ni.children || ni.childNodes;
|
101
|
+
for(var j = 0, cj; cj = cn[j]; j++){
|
102
|
+
if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
|
103
|
+
result[++ri] = cj;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}else if(mode == "+"){
|
108
|
+
var utag = tagName.toUpperCase();
|
109
|
+
for(var i = 0, n; n = ns[i]; i++){
|
110
|
+
while((n = n.nextSibling) && n.nodeType != 1);
|
111
|
+
if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
|
112
|
+
result[++ri] = n;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}else if(mode == "~"){
|
116
|
+
for(var i = 0, n; n = ns[i]; i++){
|
117
|
+
while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
|
118
|
+
if(n){
|
119
|
+
result[++ri] = n;
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
123
|
+
return result;
|
124
|
+
};
|
125
|
+
|
126
|
+
function concat(a, b){
|
127
|
+
if(b.slice){
|
128
|
+
return a.concat(b);
|
129
|
+
}
|
130
|
+
for(var i = 0, l = b.length; i < l; i++){
|
131
|
+
a[a.length] = b[i];
|
132
|
+
}
|
133
|
+
return a;
|
134
|
+
}
|
135
|
+
|
136
|
+
function byTag(cs, tagName){
|
137
|
+
if(cs.tagName || cs == document){
|
138
|
+
cs = [cs];
|
139
|
+
}
|
140
|
+
if(!tagName){
|
141
|
+
return cs;
|
142
|
+
}
|
143
|
+
var r = [], ri = -1;
|
144
|
+
tagName = tagName.toLowerCase();
|
145
|
+
for(var i = 0, ci; ci = cs[i]; i++){
|
146
|
+
if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
|
147
|
+
r[++ri] = ci;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
return r;
|
151
|
+
};
|
152
|
+
|
153
|
+
function byId(cs, attr, id){
|
154
|
+
if(cs.tagName || cs == document){
|
155
|
+
cs = [cs];
|
156
|
+
}
|
157
|
+
if(!id){
|
158
|
+
return cs;
|
159
|
+
}
|
160
|
+
var r = [], ri = -1;
|
161
|
+
for(var i = 0,ci; ci = cs[i]; i++){
|
162
|
+
if(ci && ci.id == id){
|
163
|
+
r[++ri] = ci;
|
164
|
+
return r;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
return r;
|
168
|
+
};
|
169
|
+
|
170
|
+
function byAttribute(cs, attr, value, op, custom){
|
171
|
+
var r = [], ri = -1, st = custom=="{";
|
172
|
+
var f = Castanaut.DomQuery.operators[op];
|
173
|
+
for(var i = 0, ci; ci = cs[i]; i++){
|
174
|
+
var a;
|
175
|
+
if(st){
|
176
|
+
a = Castanaut.DomQuery.getStyle(ci, attr);
|
177
|
+
}
|
178
|
+
else if(attr == "class" || attr == "className"){
|
179
|
+
a = ci.className;
|
180
|
+
}else if(attr == "for"){
|
181
|
+
a = ci.htmlFor;
|
182
|
+
}else if(attr == "href"){
|
183
|
+
a = ci.getAttribute("href", 2);
|
184
|
+
}else{
|
185
|
+
a = ci.getAttribute(attr);
|
186
|
+
}
|
187
|
+
if((f && f(a, value)) || (!f && a)){
|
188
|
+
r[++ri] = ci;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
return r;
|
192
|
+
};
|
193
|
+
|
194
|
+
function byPseudo(cs, name, value){
|
195
|
+
return Castanaut.DomQuery.pseudos[name](cs, value);
|
196
|
+
};
|
197
|
+
|
198
|
+
eval("var batch = 30803;");
|
199
|
+
|
200
|
+
var key = 30803;
|
201
|
+
|
202
|
+
function nodup(cs){
|
203
|
+
if(!cs){
|
204
|
+
return [];
|
205
|
+
}
|
206
|
+
var len = cs.length, c, i, r = cs, cj, ri = -1;
|
207
|
+
if(!len || typeof cs.nodeType != "undefined" || len == 1){
|
208
|
+
return cs;
|
209
|
+
}
|
210
|
+
var d = ++key;
|
211
|
+
cs[0]._nodup = d;
|
212
|
+
for(i = 1; c = cs[i]; i++){
|
213
|
+
if(c._nodup != d){
|
214
|
+
c._nodup = d;
|
215
|
+
}else{
|
216
|
+
r = [];
|
217
|
+
for(var j = 0; j < i; j++){
|
218
|
+
r[++ri] = cs[j];
|
219
|
+
}
|
220
|
+
for(j = i+1; cj = cs[j]; j++){
|
221
|
+
if(cj._nodup != d){
|
222
|
+
cj._nodup = d;
|
223
|
+
r[++ri] = cj;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
return r;
|
227
|
+
}
|
228
|
+
}
|
229
|
+
return r;
|
230
|
+
}
|
231
|
+
|
232
|
+
function quickDiff(c1, c2){
|
233
|
+
var len1 = c1.length;
|
234
|
+
if(!len1){
|
235
|
+
return c2;
|
236
|
+
}
|
237
|
+
var d = ++key;
|
238
|
+
for(var i = 0; i < len1; i++){
|
239
|
+
c1[i]._qdiff = d;
|
240
|
+
}
|
241
|
+
var r = [];
|
242
|
+
for(var i = 0, len = c2.length; i < len; i++){
|
243
|
+
if(c2[i]._qdiff != d){
|
244
|
+
r[r.length] = c2[i];
|
245
|
+
}
|
246
|
+
}
|
247
|
+
return r;
|
248
|
+
}
|
249
|
+
|
250
|
+
function quickId(ns, mode, root, id){
|
251
|
+
if(ns == root){
|
252
|
+
var d = root.ownerDocument || root;
|
253
|
+
return d.getElementById(id);
|
254
|
+
}
|
255
|
+
ns = getNodes(ns, mode, "*");
|
256
|
+
return byId(ns, null, id);
|
257
|
+
}
|
258
|
+
|
259
|
+
return {
|
260
|
+
getStyle : function(el, name){
|
261
|
+
return Ext.fly(el).getStyle(name);
|
262
|
+
},
|
263
|
+
compile : function(path, type){
|
264
|
+
type = type || "select";
|
265
|
+
|
266
|
+
var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
|
267
|
+
var q = path, mode, lq;
|
268
|
+
var tk = Castanaut.DomQuery.matchers;
|
269
|
+
var tklen = tk.length;
|
270
|
+
var mm;
|
271
|
+
|
272
|
+
var lmode = q.match(modeRe);
|
273
|
+
if(lmode && lmode[1]){
|
274
|
+
fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
|
275
|
+
q = q.replace(lmode[1], "");
|
276
|
+
}
|
277
|
+
while(path.substr(0, 1)=="/"){
|
278
|
+
path = path.substr(1);
|
279
|
+
}
|
280
|
+
|
281
|
+
while(q && lq != q){
|
282
|
+
lq = q;
|
283
|
+
var tm = q.match(tagTokenRe);
|
284
|
+
if(type == "select"){
|
285
|
+
if(tm){
|
286
|
+
if(tm[1] == "#"){
|
287
|
+
fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
|
288
|
+
}else{
|
289
|
+
fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
|
290
|
+
}
|
291
|
+
q = q.replace(tm[0], "");
|
292
|
+
}else if(q.substr(0, 1) != '@'){
|
293
|
+
fn[fn.length] = 'n = getNodes(n, mode, "*");';
|
294
|
+
}
|
295
|
+
}else{
|
296
|
+
if(tm){
|
297
|
+
if(tm[1] == "#"){
|
298
|
+
fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
|
299
|
+
}else{
|
300
|
+
fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
|
301
|
+
}
|
302
|
+
q = q.replace(tm[0], "");
|
303
|
+
}
|
304
|
+
}
|
305
|
+
while(!(mm = q.match(modeRe))){
|
306
|
+
var matched = false;
|
307
|
+
for(var j = 0; j < tklen; j++){
|
308
|
+
var t = tk[j];
|
309
|
+
var m = q.match(t.re);
|
310
|
+
if(m){
|
311
|
+
fn[fn.length] = t.select.replace(tplRe, function(x, i){
|
312
|
+
return m[i];
|
313
|
+
});
|
314
|
+
q = q.replace(m[0], "");
|
315
|
+
matched = true;
|
316
|
+
break;
|
317
|
+
}
|
318
|
+
}
|
319
|
+
if(!matched){
|
320
|
+
throw 'Error parsing selector, parsing failed at "' + q + '"';
|
321
|
+
}
|
322
|
+
}
|
323
|
+
if(mm[1]){
|
324
|
+
fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
|
325
|
+
q = q.replace(mm[1], "");
|
326
|
+
}
|
327
|
+
}
|
328
|
+
fn[fn.length] = "return nodup(n);\n}";
|
329
|
+
eval(fn.join(""));
|
330
|
+
return f;
|
331
|
+
},
|
332
|
+
|
333
|
+
select : function(path, root, type){
|
334
|
+
if(!root || root == document){
|
335
|
+
root = document;
|
336
|
+
}
|
337
|
+
if(typeof root == "string"){
|
338
|
+
root = document.getElementById(root);
|
339
|
+
}
|
340
|
+
var paths = path.split(",");
|
341
|
+
var results = [];
|
342
|
+
for(var i = 0, len = paths.length; i < len; i++){
|
343
|
+
var p = paths[i].replace(trimRe, "");
|
344
|
+
if(!cache[p]){
|
345
|
+
cache[p] = Castanaut.DomQuery.compile(p);
|
346
|
+
if(!cache[p]){
|
347
|
+
throw p + " is not a valid selector";
|
348
|
+
}
|
349
|
+
}
|
350
|
+
var result = cache[p](root);
|
351
|
+
if(result && result != document){
|
352
|
+
results = results.concat(result);
|
353
|
+
}
|
354
|
+
}
|
355
|
+
if(paths.length > 1){
|
356
|
+
return nodup(results);
|
357
|
+
}
|
358
|
+
return results;
|
359
|
+
},
|
360
|
+
|
361
|
+
selectNode : function(path, root){
|
362
|
+
return Castanaut.DomQuery.select(path, root)[0];
|
363
|
+
},
|
364
|
+
|
365
|
+
selectValue : function(path, root, defaultValue){
|
366
|
+
path = path.replace(trimRe, "");
|
367
|
+
if(!valueCache[path]){
|
368
|
+
valueCache[path] = Castanaut.DomQuery.compile(path, "select");
|
369
|
+
}
|
370
|
+
var n = valueCache[path](root);
|
371
|
+
n = n[0] ? n[0] : n;
|
372
|
+
var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
|
373
|
+
return ((v === null||v === undefined||v==='') ? defaultValue : v);
|
374
|
+
},
|
375
|
+
|
376
|
+
selectNumber : function(path, root, defaultValue){
|
377
|
+
var v = Castanaut.DomQuery.selectValue(path, root, defaultValue || 0);
|
378
|
+
return parseFloat(v);
|
379
|
+
},
|
380
|
+
|
381
|
+
is : function(el, ss){
|
382
|
+
if(typeof el == "string"){
|
383
|
+
el = document.getElementById(el);
|
384
|
+
}
|
385
|
+
var isArray = (el instanceof Array);
|
386
|
+
var result = Castanaut.DomQuery.filter(isArray ? el : [el], ss);
|
387
|
+
return isArray ? (result.length == el.length) : (result.length > 0);
|
388
|
+
},
|
389
|
+
|
390
|
+
filter : function(els, ss, nonMatches){
|
391
|
+
ss = ss.replace(trimRe, "");
|
392
|
+
if(!simpleCache[ss]){
|
393
|
+
simpleCache[ss] = Castanaut.DomQuery.compile(ss, "simple");
|
394
|
+
}
|
395
|
+
var result = simpleCache[ss](els);
|
396
|
+
return nonMatches ? quickDiff(result, els) : result;
|
397
|
+
},
|
398
|
+
|
399
|
+
matchers : [{
|
400
|
+
re: /^\.([\w-]+)/,
|
401
|
+
select: 'n = byClassName(n, null, " {1} ");'
|
402
|
+
}, {
|
403
|
+
re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
|
404
|
+
select: 'n = byPseudo(n, "{1}", "{2}");'
|
405
|
+
},{
|
406
|
+
re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
|
407
|
+
select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
|
408
|
+
}, {
|
409
|
+
re: /^#([\w-]+)/,
|
410
|
+
select: 'n = byId(n, null, "{1}");'
|
411
|
+
},{
|
412
|
+
re: /^@([\w-]+)/,
|
413
|
+
select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
|
414
|
+
}
|
415
|
+
],
|
416
|
+
|
417
|
+
operators : {
|
418
|
+
"=" : function(a, v){
|
419
|
+
return a == v;
|
420
|
+
},
|
421
|
+
"!=" : function(a, v){
|
422
|
+
return a != v;
|
423
|
+
},
|
424
|
+
"^=" : function(a, v){
|
425
|
+
return a && a.substr(0, v.length) == v;
|
426
|
+
},
|
427
|
+
"$=" : function(a, v){
|
428
|
+
return a && a.substr(a.length-v.length) == v;
|
429
|
+
},
|
430
|
+
"*=" : function(a, v){
|
431
|
+
return a && a.indexOf(v) !== -1;
|
432
|
+
},
|
433
|
+
"%=" : function(a, v){
|
434
|
+
return (a % v) == 0;
|
435
|
+
},
|
436
|
+
"|=" : function(a, v){
|
437
|
+
return a && (a == v || a.substr(0, v.length+1) == v+'-');
|
438
|
+
},
|
439
|
+
"~=" : function(a, v){
|
440
|
+
return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
|
441
|
+
}
|
442
|
+
},
|
443
|
+
|
444
|
+
pseudos : {
|
445
|
+
"first-child" : function(c){
|
446
|
+
var r = [], ri = -1, n;
|
447
|
+
for(var i = 0, ci; ci = n = c[i]; i++){
|
448
|
+
while((n = n.previousSibling) && n.nodeType != 1);
|
449
|
+
if(!n){
|
450
|
+
r[++ri] = ci;
|
451
|
+
}
|
452
|
+
}
|
453
|
+
return r;
|
454
|
+
},
|
455
|
+
|
456
|
+
"last-child" : function(c){
|
457
|
+
var r = [], ri = -1, n;
|
458
|
+
for(var i = 0, ci; ci = n = c[i]; i++){
|
459
|
+
while((n = n.nextSibling) && n.nodeType != 1);
|
460
|
+
if(!n){
|
461
|
+
r[++ri] = ci;
|
462
|
+
}
|
463
|
+
}
|
464
|
+
return r;
|
465
|
+
},
|
466
|
+
|
467
|
+
"nth-child" : function(c, a) {
|
468
|
+
var r = [], ri = -1;
|
469
|
+
var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
|
470
|
+
var f = (m[1] || 1) - 0, l = m[2] - 0;
|
471
|
+
for(var i = 0, n; n = c[i]; i++){
|
472
|
+
var pn = n.parentNode;
|
473
|
+
if (batch != pn._batch) {
|
474
|
+
var j = 0;
|
475
|
+
for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
|
476
|
+
if(cn.nodeType == 1){
|
477
|
+
cn.nodeIndex = ++j;
|
478
|
+
}
|
479
|
+
}
|
480
|
+
pn._batch = batch;
|
481
|
+
}
|
482
|
+
if (f == 1) {
|
483
|
+
if (l == 0 || n.nodeIndex == l){
|
484
|
+
r[++ri] = n;
|
485
|
+
}
|
486
|
+
} else if ((n.nodeIndex + l) % f == 0){
|
487
|
+
r[++ri] = n;
|
488
|
+
}
|
489
|
+
}
|
490
|
+
|
491
|
+
return r;
|
492
|
+
},
|
493
|
+
|
494
|
+
"only-child" : function(c){
|
495
|
+
var r = [], ri = -1;;
|
496
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
497
|
+
if(!prev(ci) && !next(ci)){
|
498
|
+
r[++ri] = ci;
|
499
|
+
}
|
500
|
+
}
|
501
|
+
return r;
|
502
|
+
},
|
503
|
+
|
504
|
+
"empty" : function(c){
|
505
|
+
var r = [], ri = -1;
|
506
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
507
|
+
var cns = ci.childNodes, j = 0, cn, empty = true;
|
508
|
+
while(cn = cns[j]){
|
509
|
+
++j;
|
510
|
+
if(cn.nodeType == 1 || cn.nodeType == 3){
|
511
|
+
empty = false;
|
512
|
+
break;
|
513
|
+
}
|
514
|
+
}
|
515
|
+
if(empty){
|
516
|
+
r[++ri] = ci;
|
517
|
+
}
|
518
|
+
}
|
519
|
+
return r;
|
520
|
+
},
|
521
|
+
|
522
|
+
"contains" : function(c, v){
|
523
|
+
var r = [], ri = -1;
|
524
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
525
|
+
if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
|
526
|
+
r[++ri] = ci;
|
527
|
+
}
|
528
|
+
}
|
529
|
+
return r;
|
530
|
+
},
|
531
|
+
|
532
|
+
"nodeValue" : function(c, v){
|
533
|
+
var r = [], ri = -1;
|
534
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
535
|
+
if(ci.firstChild && ci.firstChild.nodeValue == v){
|
536
|
+
r[++ri] = ci;
|
537
|
+
}
|
538
|
+
}
|
539
|
+
return r;
|
540
|
+
},
|
541
|
+
|
542
|
+
"checked" : function(c){
|
543
|
+
var r = [], ri = -1;
|
544
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
545
|
+
if(ci.checked == true){
|
546
|
+
r[++ri] = ci;
|
547
|
+
}
|
548
|
+
}
|
549
|
+
return r;
|
550
|
+
},
|
551
|
+
|
552
|
+
"not" : function(c, ss){
|
553
|
+
return Castanaut.DomQuery.filter(c, ss, true);
|
554
|
+
},
|
555
|
+
|
556
|
+
"odd" : function(c){
|
557
|
+
return this["nth-child"](c, "odd");
|
558
|
+
},
|
559
|
+
|
560
|
+
"even" : function(c){
|
561
|
+
return this["nth-child"](c, "even");
|
562
|
+
},
|
563
|
+
|
564
|
+
"nth" : function(c, a){
|
565
|
+
return c[a-1] || [];
|
566
|
+
},
|
567
|
+
|
568
|
+
"first" : function(c){
|
569
|
+
return c[0] || [];
|
570
|
+
},
|
571
|
+
|
572
|
+
"last" : function(c){
|
573
|
+
return c[c.length-1] || [];
|
574
|
+
},
|
575
|
+
|
576
|
+
"has" : function(c, ss){
|
577
|
+
var s = Castanaut.DomQuery.select;
|
578
|
+
var r = [], ri = -1;
|
579
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
580
|
+
if(s(ss, ci).length > 0){
|
581
|
+
r[++ri] = ci;
|
582
|
+
}
|
583
|
+
}
|
584
|
+
return r;
|
585
|
+
},
|
586
|
+
|
587
|
+
"next" : function(c, ss){
|
588
|
+
var is = Castanaut.DomQuery.is;
|
589
|
+
var r = [], ri = -1;
|
590
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
591
|
+
var n = next(ci);
|
592
|
+
if(n && is(n, ss)){
|
593
|
+
r[++ri] = ci;
|
594
|
+
}
|
595
|
+
}
|
596
|
+
return r;
|
597
|
+
},
|
598
|
+
|
599
|
+
"prev" : function(c, ss){
|
600
|
+
var is = Castanaut.DomQuery.is;
|
601
|
+
var r = [], ri = -1;
|
602
|
+
for(var i = 0, ci; ci = c[i]; i++){
|
603
|
+
var n = prev(ci);
|
604
|
+
if(n && is(n, ss)){
|
605
|
+
r[++ri] = ci;
|
606
|
+
}
|
607
|
+
}
|
608
|
+
return r;
|
609
|
+
}
|
610
|
+
}
|
611
|
+
};
|
612
|
+
}();
|