midas 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/.bundle/config +2 -0
  2. data/.document +5 -0
  3. data/.gitignore +32 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE +20 -0
  6. data/README.textile +21 -0
  7. data/Rakefile +84 -0
  8. data/VERSION +1 -0
  9. data/features/step_definitions/editor_steps.rb +16 -0
  10. data/features/step_definitions/web_steps.rb +205 -0
  11. data/features/support/env.rb +39 -0
  12. data/features/support/paths.rb +29 -0
  13. data/features/view_editor.feature +8 -0
  14. data/generators/midas/midas_generator.rb +1 -0
  15. data/lib/midas.rb +1 -0
  16. data/midas.gemspec +131 -0
  17. data/public/images/midas/toolbars/actions/_background.png +0 -0
  18. data/public/images/midas/toolbars/actions/_background_radio.png +0 -0
  19. data/public/images/midas/toolbars/actions/_separator.png +0 -0
  20. data/public/images/midas/toolbars/actions/extra/prefspane.png +0 -0
  21. data/public/images/midas/toolbars/actions/extra/todospane.png +0 -0
  22. data/public/images/midas/toolbars/actions/historypanel.png +0 -0
  23. data/public/images/midas/toolbars/actions/insertcharacter.png +0 -0
  24. data/public/images/midas/toolbars/actions/insertlink.png +0 -0
  25. data/public/images/midas/toolbars/actions/insertmedia.png +0 -0
  26. data/public/images/midas/toolbars/actions/insertobject.png +0 -0
  27. data/public/images/midas/toolbars/actions/inserttable.png +0 -0
  28. data/public/images/midas/toolbars/actions/inspectorpanel.png +0 -0
  29. data/public/images/midas/toolbars/actions/notespanel.png +0 -0
  30. data/public/images/midas/toolbars/actions/preview.png +0 -0
  31. data/public/images/midas/toolbars/actions/redo.png +0 -0
  32. data/public/images/midas/toolbars/actions/save.png +0 -0
  33. data/public/images/midas/toolbars/actions/undo.png +0 -0
  34. data/public/images/midas/toolbars/htmleditor/_background.png +0 -0
  35. data/public/images/midas/toolbars/htmleditor/_line_separator.png +0 -0
  36. data/public/images/midas/toolbars/htmleditor/_separator.png +0 -0
  37. data/public/images/midas/toolbars/htmleditor/buttons.png +0 -0
  38. data/public/javascripts/midas/config.js +181 -0
  39. data/public/javascripts/midas/dialog.js +9 -0
  40. data/public/javascripts/midas/midas.js +307 -0
  41. data/public/javascripts/midas/native_extensions.js +43 -0
  42. data/public/javascripts/midas/palette.js +108 -0
  43. data/public/javascripts/midas/region.js +194 -0
  44. data/public/javascripts/midas/statusbar.js +84 -0
  45. data/public/javascripts/midas/toolbar.js +255 -0
  46. data/public/javascripts/prototype.js +6001 -0
  47. data/public/midas/backcolor.html +97 -0
  48. data/public/midas/examples/bundled.html +60 -0
  49. data/public/midas/examples/iframe.html +73 -0
  50. data/public/midas/examples/index.html +73 -0
  51. data/public/midas/examples/javascript_archive.js +111 -0
  52. data/public/midas/forecolor.html +97 -0
  53. data/public/stylesheets/midas/dialog.css +2 -0
  54. data/public/stylesheets/midas/midas.css +9 -0
  55. data/public/stylesheets/midas/palette.css +50 -0
  56. data/public/stylesheets/midas/region.css +16 -0
  57. data/public/stylesheets/midas/statusbar.css +17 -0
  58. data/public/stylesheets/midas/toolbar.css +262 -0
  59. data/rails/init.rb +1 -0
  60. data/spec/javascripts/dialog_spec.js +7 -0
  61. data/spec/javascripts/fixtures/midas_fixture.html +27 -0
  62. data/spec/javascripts/fixtures/midas_styles.css +14 -0
  63. data/spec/javascripts/fixtures/native_extensions_fixture.html +5 -0
  64. data/spec/javascripts/helpers/browser_detection.js +15 -0
  65. data/spec/javascripts/helpers/event_simulation.js +505 -0
  66. data/spec/javascripts/helpers/spec_helper.js +125 -0
  67. data/spec/javascripts/midas_spec.js +284 -0
  68. data/spec/javascripts/native_extensions_spec.js +39 -0
  69. data/spec/javascripts/palette_spec.js +59 -0
  70. data/spec/javascripts/region_spec.js +441 -0
  71. data/spec/javascripts/statusbar_spec.js +61 -0
  72. data/spec/javascripts/support/jasmine.yml +82 -0
  73. data/spec/javascripts/support/jasmine_config.rb +39 -0
  74. data/spec/javascripts/support/jasmine_runner.rb +19 -0
  75. data/spec/javascripts/toolbar_spec.js +149 -0
  76. data/spec/ruby/helpers/spec_helper.rb +9 -0
  77. data/spec/ruby/midas_spec.rb +9 -0
  78. data/spec/spec.opts +1 -0
  79. data/tasks/midas_tasks.rake +105 -0
  80. metadata +166 -0
@@ -0,0 +1,29 @@
1
+ module NavigationHelpers
2
+ # Maps a name to a path. Used by the
3
+ #
4
+ # When /^I go to (.+)$/ do |page_name|
5
+ #
6
+ # step definition in web_steps.rb
7
+ #
8
+ def path_to(page_name)
9
+ case page_name
10
+
11
+ when /the editor page/
12
+ '/integration/midas.html'
13
+
14
+
15
+ # Add more mappings here.
16
+ # Here is an example that pulls values out of the Regexp:
17
+ #
18
+ # when /^(.*)'s profile page$/i
19
+ # user_profile_path(User.find_by_login($1))
20
+
21
+ else
22
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
23
+ "Now, go and add a mapping in #{__FILE__}"
24
+ end
25
+ end
26
+ end
27
+
28
+ World(NavigationHelpers)
29
+
@@ -0,0 +1,8 @@
1
+ Feature: View the editor
2
+
3
+ Scenario: Viewing the editor
4
+ When I go to the editor page
5
+ And click into the editable area
6
+
7
+ And I debug
8
+
@@ -0,0 +1 @@
1
+ # generate tool views/controller -- put things in routes
@@ -0,0 +1 @@
1
+ # basic rails hooks
@@ -0,0 +1,131 @@
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{midas}
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 = ["Jeremy Jackson"]
12
+ s.date = %q{2010-06-06}
13
+ s.description = %q{Provides a front end for editing content in a contextual way with WYSIWYG editing}
14
+ s.email = %q{jejacks0n@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.textile"
18
+ ]
19
+ s.files = [
20
+ ".bundle/config",
21
+ ".document",
22
+ ".gitignore",
23
+ "Gemfile",
24
+ "LICENSE",
25
+ "README.textile",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "features/step_definitions/editor_steps.rb",
29
+ "features/step_definitions/web_steps.rb",
30
+ "features/support/env.rb",
31
+ "features/support/paths.rb",
32
+ "features/view_editor.feature",
33
+ "generators/midas/midas_generator.rb",
34
+ "lib/midas.rb",
35
+ "midas.gemspec",
36
+ "public/images/midas/toolbars/actions/_background.png",
37
+ "public/images/midas/toolbars/actions/_background_radio.png",
38
+ "public/images/midas/toolbars/actions/_separator.png",
39
+ "public/images/midas/toolbars/actions/extra/prefspane.png",
40
+ "public/images/midas/toolbars/actions/extra/todospane.png",
41
+ "public/images/midas/toolbars/actions/historypanel.png",
42
+ "public/images/midas/toolbars/actions/insertcharacter.png",
43
+ "public/images/midas/toolbars/actions/insertlink.png",
44
+ "public/images/midas/toolbars/actions/insertmedia.png",
45
+ "public/images/midas/toolbars/actions/insertobject.png",
46
+ "public/images/midas/toolbars/actions/inserttable.png",
47
+ "public/images/midas/toolbars/actions/inspectorpanel.png",
48
+ "public/images/midas/toolbars/actions/notespanel.png",
49
+ "public/images/midas/toolbars/actions/preview.png",
50
+ "public/images/midas/toolbars/actions/redo.png",
51
+ "public/images/midas/toolbars/actions/save.png",
52
+ "public/images/midas/toolbars/actions/undo.png",
53
+ "public/images/midas/toolbars/htmleditor/_background.png",
54
+ "public/images/midas/toolbars/htmleditor/_line_separator.png",
55
+ "public/images/midas/toolbars/htmleditor/_separator.png",
56
+ "public/images/midas/toolbars/htmleditor/buttons.png",
57
+ "public/javascripts/midas/config.js",
58
+ "public/javascripts/midas/dialog.js",
59
+ "public/javascripts/midas/midas.js",
60
+ "public/javascripts/midas/native_extensions.js",
61
+ "public/javascripts/midas/palette.js",
62
+ "public/javascripts/midas/region.js",
63
+ "public/javascripts/midas/statusbar.js",
64
+ "public/javascripts/midas/toolbar.js",
65
+ "public/javascripts/prototype.js",
66
+ "public/midas/backcolor.html",
67
+ "public/midas/examples/bundled.html",
68
+ "public/midas/examples/iframe.html",
69
+ "public/midas/examples/index.html",
70
+ "public/midas/examples/javascript_archive.js",
71
+ "public/midas/forecolor.html",
72
+ "public/stylesheets/midas/dialog.css",
73
+ "public/stylesheets/midas/midas.css",
74
+ "public/stylesheets/midas/palette.css",
75
+ "public/stylesheets/midas/region.css",
76
+ "public/stylesheets/midas/statusbar.css",
77
+ "public/stylesheets/midas/toolbar.css",
78
+ "rails/init.rb",
79
+ "spec/javascripts/dialog_spec.js",
80
+ "spec/javascripts/fixtures/midas_fixture.html",
81
+ "spec/javascripts/fixtures/midas_styles.css",
82
+ "spec/javascripts/fixtures/native_extensions_fixture.html",
83
+ "spec/javascripts/helpers/browser_detection.js",
84
+ "spec/javascripts/helpers/event_simulation.js",
85
+ "spec/javascripts/helpers/spec_helper.js",
86
+ "spec/javascripts/midas_spec.js",
87
+ "spec/javascripts/native_extensions_spec.js",
88
+ "spec/javascripts/palette_spec.js",
89
+ "spec/javascripts/region_spec.js",
90
+ "spec/javascripts/statusbar_spec.js",
91
+ "spec/javascripts/support/jasmine.yml",
92
+ "spec/javascripts/support/jasmine_config.rb",
93
+ "spec/javascripts/support/jasmine_runner.rb",
94
+ "spec/javascripts/toolbar_spec.js",
95
+ "spec/ruby/helpers/spec_helper.rb",
96
+ "spec/ruby/midas_spec.rb",
97
+ "spec/spec.opts",
98
+ "tasks/midas_tasks.rake"
99
+ ]
100
+ s.homepage = %q{http://github.com/jejacks0n/midas}
101
+ s.rdoc_options = ["--charset=UTF-8"]
102
+ s.require_paths = ["lib"]
103
+ s.rubygems_version = %q{1.3.5}
104
+ s.summary = %q{A rich text editor gem for Rails}
105
+ s.test_files = [
106
+ "spec/javascripts/support/jasmine_config.rb",
107
+ "spec/javascripts/support/jasmine_runner.rb",
108
+ "spec/ruby/helpers/spec_helper.rb",
109
+ "spec/ruby/midas_spec.rb"
110
+ ]
111
+
112
+ if s.respond_to? :specification_version then
113
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
114
+ s.specification_version = 3
115
+
116
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
117
+ s.add_runtime_dependency(%q<packr>, [">= 3.1.0"])
118
+ s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
119
+ s.add_development_dependency(%q<jasmine>, [">= 0.10.3.5"])
120
+ else
121
+ s.add_dependency(%q<packr>, [">= 3.1.0"])
122
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
123
+ s.add_dependency(%q<jasmine>, [">= 0.10.3.5"])
124
+ end
125
+ else
126
+ s.add_dependency(%q<packr>, [">= 3.1.0"])
127
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
128
+ s.add_dependency(%q<jasmine>, [">= 0.10.3.5"])
129
+ end
130
+ end
131
+
@@ -0,0 +1,181 @@
1
+ Midas.Config = {
2
+
3
+ /* The stylesheet to load for the skin of the toolbar/editable regions.
4
+ */
5
+ stylesheet: '/stylesheets/midas.css',
6
+
7
+ /* Toolbars
8
+ *
9
+ * Any object you put in here will create a new toolbar.
10
+ *
11
+ * button format: [label, description, [type, action], [type, action], etc]
12
+ * type can be:
13
+ * 'button' (default) calls handleCommand and passes the key of the object (eg. save, preview, undo etc.)
14
+ * 'toggle' will toggle on or off when clicked (and otherwise behaves like a button)
15
+ * 'dialog' will open a dialog window, expects the action to be:
16
+ * a string url
17
+ * a function that returns a string url
18
+ * 'panel' will open a panel dialog, expects the action to be:
19
+ * a string url
20
+ * a function that returns a string url
21
+ * 'palette' will open a palette window, expects the action to be:
22
+ * a string url
23
+ * a function that returns a string url
24
+ * 'select' will open a select/pulldown style window, expects the action to be:
25
+ * an array
26
+ * a function that returns an array
27
+ * 'context' will call a callback function, expects the action to be:
28
+ * a function that returns a boolean to highlight the button or not
29
+ * note: if a function isn't provided, the key will be passed to the
30
+ * contextHandler (eg. backcolor, bold, etc.), in which case a
31
+ * default context will be used (there are several defined in
32
+ * Midas.Toolbar.contexts).
33
+ * 'mode' will toggle a given mode in the editor, expects the action to be:
34
+ * a string, denoting the name of the mode
35
+ * note: if a string isn't provided, the key will be passed to the
36
+ * modeHandler (eg. preview, html, etc.)
37
+ * note: it's assumed that when a specific "mode" is turned on, all other "modes" will be
38
+ * turned off (this happens automatically), thus putting the editor into a specific
39
+ * "state".
40
+ *
41
+ * If a button is an object (not an array, not a string), it's assumed that it's a button group,
42
+ * all of it's children will be expected to be buttons or button groups. A button group is
43
+ * wrapped within a div for styling. It's important to note that each of the keys, regardless of
44
+ * if it's in a group or not needs to be unique.
45
+ *
46
+ * The save action is special, in that it's handled by Midas directly, all other actions are
47
+ * handled by Midas.Region.
48
+ *
49
+ * Separators are any "button" that's not an array, and are expected to be a string. You can use
50
+ * three different separator styles: line, spacer, and flex spacer.
51
+ * '-' = line
52
+ * ' ' = spacer
53
+ * '*' = flex spacer
54
+ */
55
+ toolbars: {
56
+ actions: {
57
+ save: ['Save', 'Save this page'],
58
+ preview: ['Preview', 'Preview this page', ['toggle'], ['mode']],
59
+ sep1: ' ',
60
+ undo: ['Undo', 'Undo your last action'],
61
+ redo: ['Redo', 'Redo your last action'],
62
+ sep2: ' ',
63
+ insertlink: ['Link', 'Insert a hyperlink', ['dialog', '/midas/link']],
64
+ insertmedia: ['Media', 'Insert media', ['dialog', '/midas/media']],
65
+ inserttable: ['Table', 'Insert a table', ['dialog', '/midas/table']],
66
+ insertobject: ['Object', 'Insert an object (form, widget, etc)', ['dialog', '/midas/object']],
67
+ insertcharacter: ['Character', 'Insert special characters', ['dialog', '/midas/character']],
68
+ inspectorpanel: ['Inspector', 'Open the element inspector panel', ['panel', '/midas/inspector']],
69
+ sep3: '*',
70
+ notespanel: ['Notes', 'Open the page notes panel', ['panel', '/midas/notes']],
71
+ historypanel: ['History', 'Open the page history panel', ['panel', '/midas/history']]
72
+ },
73
+ htmleditor: {
74
+ style: ['Style', '', ['select', function() { return Midas.Config.styles }]],
75
+ formatblock: ['Block Format', '', ['select', function() { return Midas.Config.blocks }]],
76
+ sep1: '-',
77
+ //backcolor: ['Background Color', '', ['palette', '/midas/backcolor.html'], ['context']],
78
+ forecolor: ['Text Color', '', ['palette', '/midas/forecolor.html'], ['context']],
79
+ sep2: '-',
80
+ decoration: {
81
+ bold: ['Bold', '', ['context']],
82
+ italic: ['Italicize', '', ['context']],
83
+ //overline: ['Overline', '', ['context']],
84
+ strikethrough: ['Strikethrough', '', ['context']],
85
+ underline: ['Underline', '', ['context']],
86
+ sep: '-'
87
+ },
88
+ script: {
89
+ subscript: ['Subscript', '', ['context']],
90
+ superscript: ['Superscript', '', ['context']],
91
+ sep: '-'
92
+ },
93
+ justify: {
94
+ justifyleft: ['Align Left', '', ['context']],
95
+ justifycenter: ['Center', '', ['context']],
96
+ justifyright: ['Align Right', '', ['context']],
97
+ justifyfull: ['Justify Full', '', ['context']],
98
+ sep: '-'
99
+ },
100
+ list: {
101
+ insertunorderedlist: ['Unordered List', '', ['context']],
102
+ insertorderedlist: ['Numbered List', '', ['context']],
103
+ sep: '-'
104
+ },
105
+ indent: {
106
+ outdent: ['Decrease Indentation', ''],
107
+ indent: ['Increase Indentation', ''],
108
+ sep: '-'
109
+ },
110
+ //table: {
111
+ // insertrowbefore: ['Insert Row', 'Insert a table row before'],
112
+ // insertrowafter: ['Insert Row', 'Insert a table row after'],
113
+ // deleterow: ['Delete Row', 'Delete this table row'],
114
+ // insertcolumnbefore: ['Insert Column', 'Insert a table column before'],
115
+ // insertcolumnafter: ['Insert Column', 'Insert a table column after'],
116
+ // deletecolumn: ['Delete Column', 'Delete this table column'],
117
+ // sep: '-'
118
+ // },
119
+ breaks: {
120
+ horizontalrule: ['Horizontal Rule', ''],
121
+ sep: '-'
122
+ },
123
+ removeformatting: ['Remove Formatting', ''],
124
+ html: ['Edit HTML', '', ['dialog', '/midas/html']]
125
+ }
126
+ },
127
+
128
+ /* Behaviors
129
+ *
130
+ * Behaviors are used to change the default behaviors of the editor when a given button is
131
+ * clicked. For example, we prefer to add HR tags using an HR wrapped within a div with a
132
+ * classname of hr, which allows for more flexible styling. To add your own complex
133
+ * behaviors just prototype them onto Midas.Region.handle.
134
+ *
135
+ * An example behavior would be to add a new button, called buynowbutton, and providing a
136
+ * behavior like:
137
+ *
138
+ * buynowbutton: {insertElement: function() {
139
+ * return new Element('a', {href: '/buy-now', class: 'buy-now'}).update('Buy Now!');
140
+ * }}
141
+ *
142
+ * It's important to note that the this keyword inside of the callback functions applies to an
143
+ * instance of Midas.Region.
144
+ *
145
+ * Behavior Methods, and expected arguments (arguments can be provided in an array when there
146
+ * is more than one expected):
147
+ * execCommand: a string of the action to take, or an array [action to take, argument]
148
+ * insertHTML: a callback function that returns a string
149
+ * ...
150
+ */
151
+ behaviors: {
152
+ horizontalrule: {insertHTML: function() {
153
+ return '<div class="hr"><hr/></div>';
154
+ }}
155
+ },
156
+
157
+ /* CSS Classes that can be inserted using the toolbar
158
+ * -- will wrap selections in spans with a classname of whatever is selected
159
+ */
160
+ styles: [
161
+ ['red', 'Red text'],
162
+ ['bold', 'Large bold text'],
163
+ ['blue', 'Blue background']
164
+ ],
165
+
166
+ /* Block elements that can be inserted using the toolbar
167
+ * -- will wrap selections in selected element
168
+ */
169
+ blocks: [
170
+ ['<h1>', 'Heading 1 &lt;h1&gt;'],
171
+ ['<h2>', 'Heading 2 &lt;h2&gt;'],
172
+ ['<h3>', 'Heading 3 &lt;h3&gt;'],
173
+ ['<h4>', 'Heading 4 &lt;h4&gt;'],
174
+ ['<h5>', 'Heading 5 &lt;h5&gt;'],
175
+ ['<h6>', 'Heading 6 &lt;h6&gt;'],
176
+ ['<p>', 'Paragraph'],
177
+ ['<blockquote>', 'Blockquote &lt;blockquote&gt;']
178
+ ['<pre>', 'Formatted &lt;pre&gt;']
179
+ ]
180
+
181
+ };
@@ -0,0 +1,9 @@
1
+ if (!Midas) var Midas = {};
2
+ Midas.Dialog = Class.create({
3
+ version: 0.2,
4
+
5
+ initialize: function() {
6
+
7
+ }
8
+ });
9
+
@@ -0,0 +1,307 @@
1
+ var Midas = Class.create({
2
+ version: 0.2,
3
+ options: {
4
+ classname: 'editable',
5
+ saveUrl: window.location.href,
6
+ saveMethod: 'put',
7
+ configuration: null,
8
+ useIframe: false // boolean true, or a string of the document to load
9
+ },
10
+ contentWindow: window,
11
+ actionsToHandle: ['save'],
12
+
13
+ initialize: function(options, toolbarOptions, regionOptions, statusbarOptions) {
14
+ options = options || {};
15
+ if (!Midas.agentIsCapable()) throw('Midas requires a browser that has contentEditable features');
16
+ if (options['useIframe'] && !window.isTop()) {
17
+ Midas.trace('Midas will only instantiate in "top", when using an iframe');
18
+ return;
19
+ }
20
+
21
+ Midas.registerInstance(this);
22
+
23
+ this.options = Object.extend(Object.clone(this.options), options);
24
+ this.options['configuration'] = this.options['configuration'] || Midas.Config;
25
+ this.config = this.options['configuration'];
26
+
27
+ this.toolbarOptions = toolbarOptions || {};
28
+ this.statusbarOptions = statusbarOptions || {};
29
+ this.regionOptions = regionOptions || {};
30
+
31
+ this.initializeInterface();
32
+
33
+ this.setupObservers();
34
+ },
35
+
36
+ initializeInterface: function() {
37
+ this.regions = [];
38
+
39
+ if (this.options['useIframe']) {
40
+ var src = (this.options['useIframe'] === true) ? window.location.href + '?midas_regions=true' : this.options['useIframe'];
41
+
42
+ this.iframe = new Element('iframe', {
43
+ seamless: 'true',
44
+ frameborder: '0',
45
+ className: 'midas-iframe-window',
46
+ src: 'about:blank'
47
+ });
48
+
49
+ Event.observe(this.iframe, 'load', function() {
50
+ this.initializeRegions(this.iframe.contentWindow);
51
+ this.finalizeInterface();
52
+ }.bind(this));
53
+
54
+ this.iframe.src = src;
55
+ this.iframeContainer = new Element('div', {'class': 'midas-iframe-container'});
56
+ this.iframeContainer.appendChild(this.iframe);
57
+
58
+ document.body.setStyle('overflow:hidden');
59
+ document.body.appendChild(this.iframeContainer);
60
+ } else {
61
+ this.initializeRegions(this.contentWindow);
62
+ this.finalizeInterface();
63
+ }
64
+ },
65
+
66
+ initializeRegions: function(contentWindow) {
67
+ this.contentWindow = contentWindow;
68
+ Object.extend(this.regionOptions, {contentWindow: this.contentWindow, configuration: this.options['configuration']});
69
+
70
+ var body = this.contentWindow.document.body;
71
+ if (typeof(body.select) == 'function') {
72
+ this.regionElements = body.select('div.' + this.options['classname']);
73
+ } else {
74
+ this.regionElements = body.getElementsByClassName(this.options['classname']);
75
+ }
76
+
77
+ for (var i = 0; i < this.regionElements.length; ++i) {
78
+ this.regions.push(new Midas.Region(this.regionElements[i], this.regionOptions, 'midas' + this._id + '_region_' + i));
79
+ }
80
+ },
81
+
82
+ finalizeInterface: function() {
83
+ if (this.regions[0]) this.setActiveRegion(this.regions[0]);
84
+
85
+ Object.extend(this.toolbarOptions, {contentWindow: this.contentWindow, configuration: this.options['configuration']});
86
+ Object.extend(this.statusbarOptions, {contentWindow: this.contentWindow, configuration: this.options['configuration']});
87
+
88
+ this.toolbar = new Midas.Toolbar(this.toolbarOptions);
89
+ this.statusbar = new Midas.Statusbar(this.statusbarOptions);
90
+
91
+ this.resize();
92
+
93
+ },
94
+
95
+ setupObservers: function() {
96
+ window.onbeforeunload = this.onBeforeUnload.bind(this);
97
+ Event.observe(window, 'resize', this.resize.bind(this));
98
+
99
+ Event.observe(document, 'mouseup', function(e) {
100
+ var element = Event.element(e);
101
+ if (this.toolbar && (element.descendantOf(this.toolbar.element) || element == this.toolbar.element)) return;
102
+ for (var i = 0; i < this.regions.length; ++i) {
103
+ if (element == this.regions[i].element || element.descendantOf(this.regions[i].element)) return;
104
+ }
105
+
106
+ this.setActiveRegion(null);
107
+ if (this.toolbar) this.toolbar.unsetActiveButtons();
108
+ }.bind(this));
109
+
110
+ //{action: action, event: event, toolbar: this}
111
+ Event.observe(document, 'midas:button', function(e) {
112
+ if (!this.activeRegion) return;
113
+ var a = e.memo;
114
+
115
+ if (this.toolbar != a['toolbar']) return;
116
+ this.changed = true;
117
+
118
+ var handled = this.handleAction(a['action'], a['event'], a['toolbar'], a['options']);
119
+ if (!handled) this.activeRegion.handleAction(a['action'], a['event'], a['toolbar'], a['options']);
120
+ if (this.statusbar) this.statusbar.update(this.activeRegion, e);
121
+ if (this.toolbar) this.toolbar.setActiveButtons(this.regions, this.activeRegion);
122
+ }.bindAsEventListener(this));
123
+
124
+ //{mode: mode, toolbar: this}
125
+ Event.observe(document, 'midas:mode', function(e) {
126
+ if (!this.activeRegion) return;
127
+ var a = e.memo;
128
+
129
+ if (this.toolbar != a['toolbar']) return;
130
+
131
+ this.handleMode(a['mode'], a['toolbar']);
132
+ }.bindAsEventListener(this));
133
+
134
+ //{region: this, name: this.name, event: event}
135
+ Event.observe(document, 'midas:region', function(e) {
136
+ var a = e.memo;
137
+ if (this.regions.indexOf(a['region']) < 0) return;
138
+
139
+ if (a['changed']) this.changed = true;
140
+ this.setActiveRegion(a['region']);
141
+ }.bindAsEventListener(this));
142
+
143
+ //{region: this, name: this.name, event: event}
144
+ Event.observe(document, 'midas:region:update', function(e) {
145
+ var a = e.memo;
146
+
147
+ Midas.fire('region', e.memo);
148
+
149
+ if (this.regions.indexOf(a['region']) < 0) return;
150
+
151
+ if (this.statusbar) this.statusbar.update(this.activeRegion, a['event']);
152
+ if (this.toolbar) this.toolbar.setActiveButtons(this.regions, this.activeRegion);
153
+ }.bind(this));
154
+ },
155
+
156
+ setActiveRegion: function(region) {
157
+ this.activeRegion = region;
158
+ },
159
+
160
+ handleAction: function(action, event, toolbar, options) {
161
+ options = options || {};
162
+
163
+ if (this.actionsToHandle.indexOf(action) < 0) return false;
164
+ if (Object.isFunction(this[action])) return this[action].apply(this, arguments);
165
+
166
+ throw('Unhandled action "' + action + '"');
167
+ },
168
+
169
+ handleMode: function(mode, toolbar) {
170
+ //!!
171
+ },
172
+
173
+ serialize: function() {
174
+ var serialized = {};
175
+ this.regions.each(function(region) {
176
+ var value = region.serialize();
177
+ serialized[value.name] = value.content;
178
+ });
179
+ return serialized;
180
+ },
181
+
182
+ save: function() {
183
+ var method = this.options.saveMethod;
184
+ var parameters = {};
185
+ if (method.toUpperCase() != 'POST' && method.toUpperCase() != 'GET') {
186
+ parameters['_method'] = method;
187
+ }
188
+
189
+ new Ajax.Request(this.options.saveUrl, {
190
+ method: method,
191
+ parameters: Object.extend(parameters, this.serialize()),
192
+ onSuccess: function() {
193
+ this.changed = false;
194
+ }.bind(this)
195
+ });
196
+
197
+ return true;
198
+ },
199
+
200
+ resize: function() {
201
+ var view = document.viewport.getDimensions();
202
+
203
+ if (this.iframe) {
204
+ var toolbarHeight = (this.toolbar) ? this.toolbar.getHeight() : 0;
205
+ var statusbarHeight = (this.statusbar) ? this.statusbar.getHeight() : 0;
206
+ this.iframeContainer.setStyle({
207
+ height: (view.height - statusbarHeight - toolbarHeight - 10) + 'px',
208
+ width: view.width + 'px',
209
+ top: this.toolbar.getHeight() + 'px',
210
+ left: 0
211
+ });
212
+ this.iframe.setStyle({
213
+ height: (view.height - statusbarHeight - toolbarHeight - 10) + 'px',
214
+ width: view.width + 'px'
215
+ });
216
+ }
217
+ },
218
+
219
+ onBeforeUnload: function() {
220
+ if (this.changed) return "You've made changes without saving them. Are you sure you'd like to navigate away without saving them first?";
221
+ },
222
+
223
+ destroy: function() {
224
+ if (this.toolbar) this.toolbar.destroy();
225
+ if (this.statusbar) this.statusbar.destroy();
226
+ this.regions.each(function(region) {
227
+ region.destroy();
228
+ });
229
+ if (this.iframe) {
230
+ this.iframe.remove();
231
+ this.iframe = null;
232
+ }
233
+ this.toolbar = null;
234
+ this.statusbar = null;
235
+ this.regions = [];
236
+ Midas.unregisterInstance(this);
237
+ }
238
+ });
239
+
240
+ // Midas static methods
241
+ Object.extend(Midas, {
242
+ version: 0.2,
243
+ instances: [],
244
+ agentId: null,
245
+ debugMode: false,
246
+
247
+ registerInstance: function(instance) {
248
+ this.instances.push(instance);
249
+ },
250
+
251
+ unregisterInstance: function(instance) {
252
+ this.instances = this.instances.without(instance);
253
+ },
254
+
255
+ agent: function() {
256
+ if (this.agentId) return this.agentId;
257
+
258
+ var agent = navigator.userAgent.toLowerCase();
259
+
260
+ var name = null;
261
+ if ((agent.indexOf("msie") != -1) && (agent.indexOf("opera") == -1) && (agent.indexOf("webtv") == -1)) {
262
+ name = 'msie';
263
+ } else if (agent.indexOf("opera") != -1) {
264
+ name = 'opera';
265
+ } else if (agent.indexOf("gecko") != -1) {
266
+ name = 'gecko';
267
+ } else if (agent.indexOf("safari") != -1) {
268
+ name = 'safari';
269
+ } else if (agent.indexOf("konqueror") != -1) {
270
+ name = 'konqueror';
271
+ }
272
+
273
+ this.agentId = name;
274
+ return name;
275
+ },
276
+
277
+ agentIsCapable: function() {
278
+ var agent = Midas.agent();
279
+
280
+ // TODO: IE is disabled at this point because it doesn't follow the w3c standards in regards to designMode.
281
+ return (agent && document.getElementById && document.designMode && agent != 'konqueror' && agent != 'msie') ? true : false;
282
+ },
283
+
284
+ fire: function(event, memo) {
285
+ event = 'midas:' + event;
286
+ Midas.trace('Midas.fire', event, memo);
287
+
288
+ Event.fire(document, event, memo);
289
+ },
290
+
291
+ trace: function() {
292
+ var args = [];
293
+ for (var i = 0; i < arguments.length; ++i) args.push(arguments[i]);
294
+ if (Midas.debugMode && typeof(console) != 'undefined') {
295
+ try {
296
+ console.debug(args);
297
+ } catch(e1) {
298
+ try {
299
+ console.info(args);
300
+ } catch(e2) {
301
+ try { console.log(args); } catch(e3) {}
302
+ }
303
+ }
304
+ }
305
+ }
306
+ });
307
+