midas 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+