damagecontrol 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. data/README +75 -0
  2. data/README.license +5 -0
  3. data/Rakefile +111 -0
  4. data/app/controllers/admin_controller.rb +10 -0
  5. data/app/controllers/application.rb +163 -0
  6. data/app/controllers/files_controller.rb +19 -0
  7. data/app/controllers/project_controller.rb +284 -0
  8. data/app/controllers/scm_controller.rb +49 -0
  9. data/app/helpers/admin_helper.rb +2 -0
  10. data/app/helpers/application_helper.rb +3 -0
  11. data/app/helpers/project_helper.rb +2 -0
  12. data/app/views/dhtml_sites.txt +6 -0
  13. data/app/views/files/list.rhtml +4 -0
  14. data/app/views/layouts/rscm.rhtml +79 -0
  15. data/app/views/project/_bugzilla.rhtml +13 -0
  16. data/app/views/project/_changesets_list.rhtml +52 -0
  17. data/app/views/project/_cvs.rhtml +171 -0
  18. data/app/views/project/_jira.rhtml +19 -0
  19. data/app/views/project/_mooky.rhtml +23 -0
  20. data/app/views/project/_null.rhtml +0 -0
  21. data/app/views/project/_project.rhtml +36 -0
  22. data/app/views/project/_rubyforge.rhtml +19 -0
  23. data/app/views/project/_scarab.rhtml +19 -0
  24. data/app/views/project/_scms.rhtml +15 -0
  25. data/app/views/project/_sourceforge.rhtml +19 -0
  26. data/app/views/project/_starteam.rhtml +43 -0
  27. data/app/views/project/_svn.rhtml +22 -0
  28. data/app/views/project/_trac.rhtml +13 -0
  29. data/app/views/project/_trackers.rhtml +18 -0
  30. data/app/views/project/changesets.rhtml +31 -0
  31. data/app/views/project/index.rhtml +23 -0
  32. data/app/views/project/view.rhtml +70 -0
  33. data/app/views/scm/checkout_status.rhtml +44 -0
  34. data/app/views/scm/diff.rhtml +1 -0
  35. data/app/views/scm/scroll.html +27 -0
  36. data/bin/damagecontrol +7 -0
  37. data/bin/damagecontrol-webrick +2 -0
  38. data/config/database.yml +20 -0
  39. data/config/environment.rb +60 -0
  40. data/config/environments/development.rb +3 -0
  41. data/config/environments/production.rb +2 -0
  42. data/config/environments/test.rb +3 -0
  43. data/lib/damagecontrol/app.rb +74 -0
  44. data/lib/damagecontrol/build.rb +104 -0
  45. data/lib/damagecontrol/diff_htmlizer.rb +82 -0
  46. data/lib/damagecontrol/diff_parser.rb +153 -0
  47. data/lib/damagecontrol/directories.rb +126 -0
  48. data/lib/damagecontrol/poller.rb +72 -0
  49. data/lib/damagecontrol/project.rb +213 -0
  50. data/lib/damagecontrol/project_dependencies.rb +8 -0
  51. data/lib/damagecontrol/scm_web.rb +50 -0
  52. data/lib/damagecontrol/standard_persister.rb +49 -0
  53. data/lib/damagecontrol/tracker.rb +164 -0
  54. data/lib/damagecontrol/visitor/build_executor.rb +32 -0
  55. data/lib/damagecontrol/visitor/diff_persister.rb +41 -0
  56. data/lib/damagecontrol/visitor/rss_writer.rb +43 -0
  57. data/lib/damagecontrol/visitor/yaml_persister.rb +71 -0
  58. data/public/404.html +6 -0
  59. data/public/500.html +6 -0
  60. data/public/dispatch.cgi +10 -0
  61. data/public/dispatch.fcgi +7 -0
  62. data/public/dispatch.rb +10 -0
  63. data/public/images/16x16/about.png +0 -0
  64. data/public/images/16x16/bug_green.png +0 -0
  65. data/public/images/16x16/bug_red.png +0 -0
  66. data/public/images/16x16/bug_yellow.png +0 -0
  67. data/public/images/16x16/component.png +0 -0
  68. data/public/images/16x16/console.png +0 -0
  69. data/public/images/16x16/console_error.png +0 -0
  70. data/public/images/16x16/document_add.png +0 -0
  71. data/public/images/16x16/document_delete.png +0 -0
  72. data/public/images/16x16/document_edit.png +0 -0
  73. data/public/images/16x16/document_exchange.png +0 -0
  74. data/public/images/16x16/document_new.png +0 -0
  75. data/public/images/16x16/document_warning.png +0 -0
  76. data/public/images/16x16/safe.png +0 -0
  77. data/public/images/16x16/scroll_information.png +0 -0
  78. data/public/images/16x16/wrench.png +0 -0
  79. data/public/images/24x24/box_delete.png +0 -0
  80. data/public/images/24x24/box_into.png +0 -0
  81. data/public/images/24x24/box_new.png +0 -0
  82. data/public/images/24x24/console_network.png +0 -0
  83. data/public/images/24x24/document_edit.png +0 -0
  84. data/public/images/24x24/find.png +0 -0
  85. data/public/images/24x24/folders.png +0 -0
  86. data/public/images/24x24/garbage.png +0 -0
  87. data/public/images/24x24/gear_connection.png +0 -0
  88. data/public/images/24x24/gear_delete.png +0 -0
  89. data/public/images/24x24/gears_run.png +0 -0
  90. data/public/images/24x24/home.png +0 -0
  91. data/public/images/24x24/navigate_left.png +0 -0
  92. data/public/images/24x24/navigate_right.png +0 -0
  93. data/public/images/24x24/package_new.png +0 -0
  94. data/public/images/24x24/safe.png +0 -0
  95. data/public/images/24x24/safe_new.png +0 -0
  96. data/public/images/24x24/safe_out.png +0 -0
  97. data/public/images/24x24/scroll_information.png +0 -0
  98. data/public/images/24x24/stop.png +0 -0
  99. data/public/images/24x24/wrench.png +0 -0
  100. data/public/images/README.license +2 -0
  101. data/public/images/blue-16.gif +0 -0
  102. data/public/images/blue-32.gif +0 -0
  103. data/public/images/bugzilla.png +0 -0
  104. data/public/images/cvs.png +0 -0
  105. data/public/images/footer.gif +0 -0
  106. data/public/images/green-128.gif +0 -0
  107. data/public/images/green-16.gif +0 -0
  108. data/public/images/green-32.gif +0 -0
  109. data/public/images/grey-16.gif +0 -0
  110. data/public/images/grey-32.gif +0 -0
  111. data/public/images/jira.gif +0 -0
  112. data/public/images/red-16.gif +0 -0
  113. data/public/images/red-32.gif +0 -0
  114. data/public/images/red-pulse-32.gif +0 -0
  115. data/public/images/rss.gif +0 -0
  116. data/public/images/rubyforge.png +0 -0
  117. data/public/images/scarab.gif +0 -0
  118. data/public/images/sourceforge.gif +0 -0
  119. data/public/images/starteam.png +0 -0
  120. data/public/images/svnlogo64.png +0 -0
  121. data/public/images/trac.png +0 -0
  122. data/public/index.html +1 -0
  123. data/public/javascripts/dw_event.js +34 -0
  124. data/public/javascripts/dw_tooltip.js +86 -0
  125. data/public/javascripts/dw_viewport.js +55 -0
  126. data/public/javascripts/pngfix.js +29 -0
  127. data/public/javascripts/toggle_diff.js +25 -0
  128. data/public/licenses/DAMAGECONTROL.license +28 -0
  129. data/public/licenses/INCORS.license +32 -0
  130. data/public/stylesheets/diff.css +23 -0
  131. data/public/stylesheets/style.css +307 -0
  132. data/script/breakpointer +5 -0
  133. data/script/console +30 -0
  134. data/script/generate +70 -0
  135. data/script/server +61 -0
  136. data/test/damagecontrol/a_program.rb +3 -0
  137. data/test/damagecontrol/a_slow_program.rb +3 -0
  138. data/test/damagecontrol/build_test.rb +59 -0
  139. data/test/damagecontrol/diff_htmlizer_test.rb +31 -0
  140. data/test/damagecontrol/diff_parser_test.rb +61 -0
  141. data/test/damagecontrol/file_ext.rb +12 -0
  142. data/test/damagecontrol/poller_test.rb +56 -0
  143. data/test/damagecontrol/project_test.rb +144 -0
  144. data/test/damagecontrol/scm_web_test.rb +22 -0
  145. data/test/damagecontrol/test.diff +38 -0
  146. data/test/damagecontrol/test.html +40 -0
  147. data/test/damagecontrol/tracker_test.rb +48 -0
  148. data/test/damagecontrol/visitor/changesets.rss +34 -0
  149. data/test/damagecontrol/visitor/diff_persister_test.rb +49 -0
  150. data/test/damagecontrol/visitor/rss_writer_test.rb +40 -0
  151. data/test/damagecontrol/visitor/yaml_persister_test.rb +40 -0
  152. data/test/functional/admin_controller_test.rb +17 -0
  153. data/test/functional/project_controller_test.rb +17 -0
  154. data/test/test_helper.rb +14 -0
  155. metadata +245 -0
@@ -0,0 +1,164 @@
1
+ require 'rscm/path_converter'
2
+
3
+ module DamageControl
4
+ module Tracker
5
+
6
+ # Simple superclass so we can easily include mixins
7
+ # for all subclasses in one fell swoop.
8
+ class Base #:nodoc:
9
+ def htmlize(str)
10
+ str.gsub(/\n/, "<br>")
11
+ end
12
+ end
13
+
14
+ class Null < Base
15
+ def name
16
+ "No Tracker"
17
+ end
18
+
19
+ def highlight(s)
20
+ htmlize(s)
21
+ end
22
+
23
+ def url
24
+ "#"
25
+ end
26
+
27
+ end
28
+
29
+ class Bugzilla < Base
30
+ attr_accessor :url
31
+
32
+ def initialize(url=nil)
33
+ @url = url
34
+ end
35
+
36
+ def name
37
+ "Bugzilla"
38
+ end
39
+
40
+ def highlight(s)
41
+ url = RSCM::PathConverter.ensure_trailing_slash(@url)
42
+ if (url)
43
+ htmlize(s.gsub(/#([0-9]+)/, "<a href=\"#{url}show_bug.cgi?id=\\1\">#\\1</a>"))
44
+ else
45
+ htmlize(s)
46
+ end
47
+ end
48
+ end
49
+
50
+ class Trac < Base
51
+ attr_accessor :url
52
+
53
+ def initialize(url=nil)
54
+ @url = url
55
+ end
56
+
57
+ def name
58
+ "Trac"
59
+ end
60
+
61
+ def highlight(s)
62
+ url = RSCM::PathConverter.ensure_trailing_slash(@url)
63
+ if (url)
64
+ htmlize(s.gsub(/#([0-9]+)/, "<a href=\"#{url}/ticket/\\1\">#\\1</a>"))
65
+ else
66
+ htmlize(s)
67
+ end
68
+ end
69
+ end
70
+
71
+ class JIRA < Base
72
+ attr_accessor :baseurl
73
+ attr_accessor :project_id
74
+
75
+ def initialize(baseurl=nil, project_id=nil)
76
+ @baseurl, @project_id = baseurl, project_id
77
+ end
78
+
79
+ def name
80
+ "JIRA"
81
+ end
82
+
83
+ def url
84
+ "#{RSCM::PathConverter.ensure_trailing_slash(baseurl)}browse/#{project_id}"
85
+ end
86
+
87
+ def highlight(s)
88
+ url = RSCM::PathConverter.ensure_trailing_slash(baseurl)
89
+ if(url)
90
+ htmlize(s.gsub(/([A-Z]+-[0-9]+)/, "<a href=\"#{url}browse/\\1\">\\1</a>"))
91
+ else
92
+ htmlize(s)
93
+ end
94
+ end
95
+ end
96
+
97
+ class SourceForge < Base
98
+ PATTERN = /#([0-9]+)/
99
+
100
+ attr_accessor :group_id
101
+ attr_accessor :tracker_id
102
+
103
+ def initialize(group_id=nil, tracker_id=nil)
104
+ @group_id, @tracker_id = group_id, tracker_id
105
+ end
106
+
107
+ def name
108
+ "SourceForge"
109
+ end
110
+
111
+ def url
112
+ "http://sourceforge.net/tracker/?group_id=#{group_id}"
113
+ end
114
+
115
+ def highlight(message)
116
+ htmlize(message.gsub(PATTERN,"<a href=\"http://sourceforge.net/tracker/index.php?func=detail&aid=\\1&group_id=#{group_id}&atid=#{tracker_id}\">#\\1</a>"))
117
+ end
118
+ end
119
+
120
+ class RubyForge < SourceForge
121
+
122
+ # TODO: share the same rhtml template
123
+
124
+ def name
125
+ "RubyForge"
126
+ end
127
+
128
+ def url
129
+ "http://rubyforge.org/tracker/?group_id=#{group_id}"
130
+ end
131
+
132
+ def highlight(message)
133
+ htmlize(message.gsub(PATTERN,"<a href=\"http://rubyforge.org/tracker/index.php?func=detail&aid=\\1&group_id=#{group_id}&atid=#{tracker_id}\">#\\1</a>"))
134
+ end
135
+ end
136
+
137
+ class Scarab < Base
138
+ attr_accessor :baseurl
139
+ attr_accessor :module_key
140
+
141
+ def initialize(baseurl=nil, module_key=nil)
142
+ @baseurl, @module_key = baseurl, module_key
143
+ end
144
+
145
+ def name
146
+ "Scarab"
147
+ end
148
+
149
+ def url
150
+ baseurl
151
+ end
152
+
153
+ def highlight(s)
154
+ url = RSCM::PathConverter.ensure_trailing_slash(baseurl)
155
+ if (url)
156
+ htmlize(s.gsub(/(#{module_key}[0-9]+)/, "<a href=\"#{url}issues/id/\\1\">\\1</a>"))
157
+ else
158
+ htmlize(s)
159
+ end
160
+ end
161
+ end
162
+
163
+ end
164
+ end
@@ -0,0 +1,32 @@
1
+ require 'rscm/changes'
2
+ require 'damagecontrol/directories'
3
+
4
+ module DamageControl
5
+ module Visitor
6
+
7
+ # Visitor that executes a build for each visited changeset.
8
+ # TODO: THIS CLASS IS NOT USED YET - FINISH IT. PASS A BLOCK TO CTOR.
9
+ class BuildExecutor
10
+ # Creates a new BuildExecutor that will build the project for
11
+ # each visited changeset. The +description+ will be persisted
12
+ # with the build information to record what triggered the build.
13
+ #
14
+ def initialize(project, description)
15
+ @project = project
16
+ end
17
+
18
+ def visit_changesets(changesets)
19
+ end
20
+
21
+ def visit_changeset(changeset)
22
+ Log.info "Checking out changeset #{changeset.id} for #{@project.name}"
23
+ project.checkout(changeset.id)
24
+ Log.info "Building #{@project.name}"
25
+ end
26
+
27
+ def visit_change(change)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,41 @@
1
+ require 'rscm/changes'
2
+ require 'rscm/logging'
3
+ require 'damagecontrol/directories'
4
+
5
+ module DamageControl
6
+ module Visitor
7
+
8
+ # Visitor that persists unified diffs to disk.
9
+ #
10
+ class DiffPersister
11
+ # Creates a new Differ that will persist diffs to file.
12
+ #
13
+ def initialize(scm, project_name)
14
+ @scm, @project_name = scm, project_name
15
+ end
16
+
17
+ def visit_changesets(changesets)
18
+ end
19
+
20
+ def visit_changeset(changeset)
21
+ @changeset = changeset
22
+ Log.info "Writing diffs for #{@project_name} changeset #{changeset.identifier}"
23
+ end
24
+
25
+ def visit_change(change)
26
+ diff_file = Directories.diff_file(@project_name, @changeset, change)
27
+ Log.info " Writing diff for #{change.path} -> #{diff_file}"
28
+ checkout_dir = Directories.checkout_dir(@project_name)
29
+ @scm.diff(checkout_dir, change) do |diff_io|
30
+ FileUtils.mkdir_p(File.dirname(diff_file))
31
+ File.open(diff_file, "w") do |io|
32
+ diff_io.each_line do |line|
33
+ io.write(line)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,43 @@
1
+ module DamageControl
2
+ module Visitor
3
+ # Visitor that writes RSS for ChangeSets.
4
+ class RssWriter
5
+
6
+ # Creates a new RssWriter that will populate the +rss+
7
+ # object when it is accepted by a ChangeSets object.
8
+ def initialize(rss, title, link, description, message_linker, change_linker)
9
+ raise "title" unless title
10
+ raise "link" unless link
11
+ raise "description" unless description
12
+ raise "message_linker" unless message_linker
13
+ raise "change_linker" unless change_linker
14
+
15
+ @rss, @title, @link, @description, @message_linker, @change_linker = rss, title, link, description, message_linker, change_linker
16
+ end
17
+
18
+ def visit_changesets(changesets)
19
+ @rss.channel.title = @title
20
+ @rss.channel.link = @link
21
+ @rss.channel.description = @description
22
+ @rss.channel.generator = "RSCM - Ruby Source Control Management"
23
+ end
24
+
25
+ def visit_changeset(changeset)
26
+ @item = @rss.items.new_item
27
+
28
+ @item.pubDate = changeset.time
29
+ @item.author = changeset.developer
30
+ @item.title = changeset.message
31
+ @item.link = @change_linker.changeset_url(changeset, true)
32
+
33
+ @item.description = "<b>#{changeset.developer}</b><br/>\n"
34
+ @item.description << @message_linker.highlight(changeset.message).gsub(/\n/, "<br/>\n") << "<p/>\n"
35
+ end
36
+
37
+ def visit_change(change)
38
+ @item.description << @change_linker.change_url(change, true) << "<br/>\n"
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,71 @@
1
+ require 'yaml'
2
+ require 'rscm/changes'
3
+ require 'rscm/abstract_scm'
4
+
5
+ module DamageControl
6
+ module Visitor
7
+ # Visitor that saves each ChangeSet in a folder with the name
8
+ # of each ChangeSet's +identifier+.
9
+ #
10
+ # Is also able to load changesets.
11
+ #
12
+ class YamlPersister
13
+
14
+ def initialize(changesets_dir)
15
+ @changesets_dir = changesets_dir
16
+ end
17
+
18
+ def visit_changesets(changesets)
19
+ end
20
+
21
+ def visit_changeset(changeset)
22
+ changeset_file = "#{@changesets_dir}/#{changeset.identifier.to_s}/changeset.yaml"
23
+ dir = File.dirname(changeset_file)
24
+ FileUtils.mkdir_p(dir)
25
+ File.open(changeset_file, "w") do |io|
26
+ YAML::dump(changeset, io)
27
+ end
28
+ end
29
+
30
+ def visit_change(change)
31
+ end
32
+
33
+ #### Non-visitor methods (for loading)
34
+
35
+ # Loads +prior+ number of changesets upto +last_changeset_identifier+.
36
+ # +last_changeset_identifier+ should be the dirname of the folder containing
37
+ # the last changeset.
38
+ #
39
+ def load_upto(last_changeset_identifier, prior)
40
+ last = identifiers.index(last_changeset_identifier)
41
+
42
+ changesets = RSCM::ChangeSets.new
43
+ if(last)
44
+ first = last - prior + 1
45
+ first = 0 if first < 0
46
+
47
+ identifiers[first..last].each do |identifier|
48
+ changesets.add(YAML::load_file("#{@changesets_dir}/#{identifier.to_s}/changeset.yaml"))
49
+ end
50
+ end
51
+ changesets
52
+ end
53
+
54
+ # Returns a sorted array of Time or int representing the changeset directories.
55
+ #
56
+ def identifiers
57
+ # This is pretty quick - even with a lot of directories.
58
+ # TODO: the method is called 5 times for a page refresh!
59
+ dirs = Dir["#{@changesets_dir}/*"].find_all {|f| File.directory?(f) && File.exist?("#{f}/changeset.yaml")}
60
+ # Turn them into ints so they can be sorted.
61
+ dirs.collect { |dir| File.basename(dir).to_identifier }.sort
62
+ end
63
+
64
+ # Returns the identifier of the latest changeset.
65
+ #
66
+ def latest_identifier
67
+ identifiers[-1]
68
+ end
69
+ end
70
+ end
71
+ end
data/public/404.html ADDED
@@ -0,0 +1,6 @@
1
+ <html>
2
+ <body>
3
+ <h1>File not found</h1>
4
+ <p>Change this error message for pages not found in public/404.html</p>
5
+ </body>
6
+ </html>
data/public/500.html ADDED
@@ -0,0 +1,6 @@
1
+ <html>
2
+ <body>
3
+ <h1>Application error (Apache)</h1>
4
+ <p>Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html</p>
5
+ </body>
6
+ </html>
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
4
+
5
+ # If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
6
+ # "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
7
+ require "dispatcher"
8
+
9
+ ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) }
10
+ Dispatcher.dispatch
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + "/../config/environment"
4
+ require 'dispatcher'
5
+ require 'fcgi'
6
+
7
+ FCGI.each_cgi { |cgi| Dispatcher.dispatch(cgi) }
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
4
+
5
+ # If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
6
+ # "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
7
+ require "dispatcher"
8
+
9
+ ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) }
10
+ Dispatcher.dispatch
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,2 @@
1
+ All images in the sub-folders 16x16 and 24x24 are covered by the terms in the public/licenses/INCORS.license file.
2
+ The other images are covered by DamageControl's license in public/licenses/DAMAGECONTROL.license.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/public/index.html ADDED
@@ -0,0 +1 @@
1
+ <html><head><META HTTP-EQUIV="Refresh" CONTENT="0;URL=_doc/index.html"></head></html>
@@ -0,0 +1,34 @@
1
+ /*************************************************************************
2
+ dw_event.js (version date Feb 2004)
3
+
4
+ This code is from Dynamic Web Coding at http://www.dyn-web.com/
5
+ See Terms of Use at http://www.dyn-web.com/bus/terms.html
6
+ regarding conditions under which you may use this code.
7
+ This notice must be retained in the code as is!
8
+ *************************************************************************/
9
+
10
+ var dw_event = {
11
+
12
+ add: function(obj, etype, fp, cap) {
13
+ cap = cap || false;
14
+ if (obj.addEventListener) obj.addEventListener(etype, fp, cap);
15
+ else if (obj.attachEvent) obj.attachEvent("on" + etype, fp);
16
+ },
17
+
18
+ remove: function(obj, etype, fp, cap) {
19
+ cap = cap || false;
20
+ if (obj.removeEventListener) obj.removeEventListener(etype, fp, cap);
21
+ else if (obj.detachEvent) obj.detachEvent("on" + etype, fp);
22
+ },
23
+
24
+ DOMit: function(e) {
25
+ e = e? e: window.event;
26
+ e.tgt = e.srcElement? e.srcElement: e.target;
27
+
28
+ if (!e.preventDefault) e.preventDefault = function () { return false; }
29
+ if (!e.stopPropagation) e.stopPropagation = function () { if (window.event) window.event.cancelBubble = true; }
30
+
31
+ return e;
32
+ }
33
+
34
+ }