Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

second commit (most of the interface ect, poorly tested)

  • Loading branch information...
commit 07a6cfd2524de79849ef8ddbffac319865c5e55d 1 parent e9071aa
@jejacks0n jejacks0n authored
Showing with 3,350 additions and 89 deletions.
  1. +1 −1  .rvmrc
  2. BIN  .sass-cache/63e3533fe05f0615a0ad89f416a339a42772a0c1/testing.scssc
  3. BIN  .sass-cache/ab32eda67f412063abde8784e7aaf5ea468acdbf/test.scssc
  4. BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/carmenta_editor.scssc
  5. BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/dialog.scssc
  6. BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/modal.scssc
  7. BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/panel.scssc
  8. BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/statusbar.scssc
  9. BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/toolbar.scssc
  10. +13 −3 Gemfile
  11. +126 −44 Gemfile.lock
  12. +1 −1  Rakefile
  13. BIN  app/assets/images/carmenta/clippy.png
  14. BIN  app/assets/images/carmenta/loading-dark.gif
  15. BIN  app/assets/images/carmenta/loading-light.gif
  16. BIN  app/assets/images/carmenta/toolbar/editable/buttons.png
  17. BIN  app/assets/images/carmenta/toolbar/primary/_expander.png
  18. BIN  app/assets/images/carmenta/toolbar/primary/_pressed.png
  19. BIN  app/assets/images/carmenta/toolbar/primary/historypanel.png
  20. BIN  app/assets/images/carmenta/toolbar/primary/insertcharacter.png
  21. BIN  app/assets/images/carmenta/toolbar/primary/insertlink.png
  22. BIN  app/assets/images/carmenta/toolbar/primary/insertmedia.png
  23. BIN  app/assets/images/carmenta/toolbar/primary/inserttable.png
  24. BIN  app/assets/images/carmenta/toolbar/primary/inspectorpanel.png
  25. BIN  app/assets/images/carmenta/toolbar/primary/notespanel.png
  26. BIN  app/assets/images/carmenta/toolbar/primary/objectspanel.png
  27. BIN  app/assets/images/carmenta/toolbar/primary/preview.png
  28. BIN  app/assets/images/carmenta/toolbar/primary/redo.png
  29. BIN  app/assets/images/carmenta/toolbar/primary/save.png
  30. BIN  app/assets/images/carmenta/toolbar/primary/todospanel.png
  31. BIN  app/assets/images/carmenta/toolbar/primary/undo.png
  32. BIN  app/assets/images/rails.png
  33. +9 −6 app/assets/javascripts/application.js
  34. +138 −0 app/assets/javascripts/carmenta/carmenta_editor.js.coffee
  35. +182 −0 app/assets/javascripts/carmenta/config.js.coffee
  36. +97 −0 app/assets/javascripts/carmenta/dialog.js.coffee
  37. 0  vendor/assets/stylesheets/.gitkeep → app/assets/javascripts/carmenta/dialogs/common_dialogs.js.coffee
  38. +5 −0 app/assets/javascripts/carmenta/history_buffer.js.coffee
  39. +145 −0 app/assets/javascripts/carmenta/modal.js.coffee
  40. 0  app/assets/javascripts/carmenta/modals/common_modals.js.coffee
  41. +29 −0 app/assets/javascripts/carmenta/palette.js.coffee
  42. +98 −0 app/assets/javascripts/carmenta/panel.js.coffee
  43. +31 −0 app/assets/javascripts/carmenta/regions/editable.js.coffee
  44. +7 −0 app/assets/javascripts/carmenta/regions/snippet.js.coffee
  45. +40 −0 app/assets/javascripts/carmenta/select.js.coffee
  46. +17 −0 app/assets/javascripts/carmenta/statusbar.js.coffee
  47. +126 −0 app/assets/javascripts/carmenta/toolbar.button.js.coffee
  48. +18 −0 app/assets/javascripts/carmenta/toolbar.button_group.js.coffee
  49. +58 −0 app/assets/javascripts/carmenta/toolbar.expander.js.coffee
  50. +67 −0 app/assets/javascripts/carmenta/toolbar.js.coffee
  51. +34 −0 app/assets/javascripts/carmenta/websocket.js.coffee
  52. +10 −0 app/assets/javascripts/vendor.js
  53. +5 −3 app/assets/stylesheets/application.css
  54. +15 −0 app/assets/stylesheets/carmenta/carmenta_editor.scss
  55. +136 −0 app/assets/stylesheets/carmenta/dialog.scss
  56. +88 −0 app/assets/stylesheets/carmenta/modal.scss
  57. +17 −0 app/assets/stylesheets/carmenta/statusbar.scss
  58. +267 −0 app/assets/stylesheets/carmenta/toolbar.scss
  59. +0 −3  app/controllers/application_controller.rb
  60. +27 −0 app/controllers/carmenta_controller.rb
  61. +2 −0  app/views/carmenta/_modal_link.html.haml
  62. +10 −0 app/views/carmenta/_modal_media.html.haml
  63. +98 −0 app/views/carmenta/_palette_backcolor.html.haml
  64. +98 −0 app/views/carmenta/_palette_forecolor.html.haml
  65. +15 −0 app/views/carmenta/_panel_notes.html.haml
  66. +1 −0  app/views/carmenta/_panel_todos.html.haml
  67. +10 −0 app/views/carmenta/_select_formatblock.html.haml
  68. +4 −0 app/views/carmenta/_select_style.html.haml
  69. +10 −0 app/views/carmenta/show.html.haml
  70. +0 −14 app/views/layouts/application.html.erb
  71. +11 −0 app/views/layouts/toolbar.html.haml
  72. +1 −1  config.ru
  73. +1 −1  config/application.rb
  74. +8 −0 config/cucumber.yml
  75. +14 −3 config/database.yml
  76. +1 −1  config/environment.rb
  77. +1 −1  config/environments/development.rb
  78. +1 −1  config/environments/production.rb
  79. +1 −1  config/environments/test.rb
  80. +77 −0 config/evergreen.rb
  81. +1 −1  config/initializers/secret_token.rb
  82. +2 −2 config/initializers/session_store.rb
  83. +12 −2 config/routes.rb
  84. +15 −0 db/schema.rb
  85. +9 −0 features/editing/basic.feature
  86. +14 −0 features/step_definitions/debug_steps.rb
  87. +211 −0 features/step_definitions/web_steps.rb
  88. +46 −0 features/support/env.rb
  89. +33 −0 features/support/paths.rb
  90. +39 −0 features/support/selectors.rb
  91. +39 −0 lib/server.rb
  92. +57 −0 lib/tasks/cucumber.rake
  93. +10 −0 script/cucumber
  94. +15 −0 spec/javascripts/carmenta/camenta_editor_spec.js.coffee
  95. +7 −0 spec/javascripts/carmenta/toolbar_button_group_spec.js.coffee
  96. +8 −0 spec/javascripts/carmenta/toolbar_button_spec.js.coffee
  97. +31 −0 spec/javascripts/carmenta/toolbar_spec.js.coffee
  98. +1 −0  spec/javascripts/spec_helper.js
  99. 0  vendor/assets/javascripts/{jquery.js → jquery-1.6.js}
  100. +100 −0 vendor/assets/javascripts/jquery-ui-1.8.12.custom.min.js
  101. +96 −0 vendor/assets/javascripts/jquery.cookie.js
  102. +173 −0 vendor/assets/javascripts/jquery.easing.js
  103. +178 −0 vendor/assets/javascripts/jquery.json2.js
  104. 0  vendor/assets/javascripts/{jquery_ujs.js → jquery.ujs.js}
  105. +25 −0 vendor/assets/javascripts/jquery.uri.js
  106. +57 −0 vendor/assets/javascripts/jquery.websocket.js
View
2  .rvmrc
@@ -1,4 +1,4 @@
-rvm 1.9.2@mercury
+rvm 1.9.2@carmenta
export RUBY_HEAP_MIN_SLOTS=1000000
export RUBY_HEAP_SLOTS_INCREMENT=1000000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
View
BIN  .sass-cache/63e3533fe05f0615a0ad89f416a339a42772a0c1/testing.scssc
Binary file not shown
View
BIN  .sass-cache/ab32eda67f412063abde8784e7aaf5ea468acdbf/test.scssc
Binary file not shown
View
BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/carmenta_editor.scssc
Binary file not shown
View
BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/dialog.scssc
Binary file not shown
View
BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/modal.scssc
Binary file not shown
View
BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/panel.scssc
Binary file not shown
View
BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/statusbar.scssc
Binary file not shown
View
BIN  .sass-cache/c1b3d74eb7daa2a4600555fa1b01931a985a16df/toolbar.scssc
Binary file not shown
View
16 Gemfile
@@ -1,11 +1,18 @@
source 'http://rubygems.org'
-gem 'rails', :git => 'git://github.com/rails/rails.git'
+gem 'rails', '3.1.0.beta1'
gem 'mysql2'
gem 'sass'
gem 'coffee-script'
gem 'uglifier'
+gem 'haml'
+gem 'haml-rails'
+
+gem "redis"
+gem 'eventmachine', :git => 'git://github.com/eventmachine/eventmachine.git'
+gem "em-hiredis"
+gem "em-websocket"
group :development do
end
@@ -13,9 +20,12 @@ end
group :development, :test do
gem 'thin'
gem 'ruby-debug19', :require => 'ruby-debug'
+ gem 'evergreen', :git => 'git://github.com/jnicklas/evergreen.git', :submodules => true, :require => 'evergreen/rails'
end
group :test do
- # Pretty printed test output
- gem 'turn', :require => false
+ gem 'cucumber-rails'
+ gem 'capybara-firebug'
+ gem 'capybara'
+ gem 'database_cleaner'
end
View
170 Gemfile.lock
@@ -1,73 +1,119 @@
GIT
- remote: git://github.com/rails/rails.git
- revision: bff374050d5a7e237fda98a1d4cc6256484e94f2
+ remote: git://github.com/eventmachine/eventmachine.git
+ revision: 5398facee0279ae435cef6a69f9a1236ade4dc20
specs:
- actionmailer (3.1.0.beta)
- actionpack (= 3.1.0.beta)
+ eventmachine (1.0.0.beta.3)
+
+GIT
+ remote: git://github.com/jnicklas/evergreen.git
+ revision: ac64d51b92a6d19092ea880cad1b30427e92ab8f
+ submodules: true
+ specs:
+ evergreen (0.4.0)
+ capybara (~> 0.4.0)
+ coffee-script (~> 2.1)
+ json_pure (>= 1.0.0)
+ launchy (>= 0.3.5)
+ sinatra (>= 1.1)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ actionmailer (3.1.0.beta1)
+ actionpack (= 3.1.0.beta1)
mail (~> 2.3.0)
- actionpack (3.1.0.beta)
- activemodel (= 3.1.0.beta)
- activesupport (= 3.1.0.beta)
+ actionpack (3.1.0.beta1)
+ activemodel (= 3.1.0.beta1)
+ activesupport (= 3.1.0.beta1)
builder (~> 3.0.0)
erubis (~> 2.7.0)
i18n (~> 0.6.0beta1)
rack (~> 1.3.0.beta)
- rack-cache (~> 1.0.0)
+ rack-cache (~> 1.0.1)
rack-mount (~> 0.7.2)
rack-test (~> 0.6.0)
sprockets (~> 2.0.0.beta.2)
- tzinfo (~> 0.3.23)
- activemodel (3.1.0.beta)
- activesupport (= 3.1.0.beta)
+ tzinfo (~> 0.3.27)
+ activemodel (3.1.0.beta1)
+ activesupport (= 3.1.0.beta1)
bcrypt-ruby (~> 2.1.4)
builder (~> 3.0.0)
i18n (~> 0.6.0beta1)
- activerecord (3.1.0.beta)
- activemodel (= 3.1.0.beta)
- activesupport (= 3.1.0.beta)
+ activerecord (3.1.0.beta1)
+ activemodel (= 3.1.0.beta1)
+ activesupport (= 3.1.0.beta1)
arel (~> 2.1.0)
- tzinfo (~> 0.3.23)
- activeresource (3.1.0.beta)
- activemodel (= 3.1.0.beta)
- activesupport (= 3.1.0.beta)
- activesupport (3.1.0.beta)
- multi_json (~> 1.0.0)
- rails (3.1.0.beta)
- actionmailer (= 3.1.0.beta)
- actionpack (= 3.1.0.beta)
- activerecord (= 3.1.0.beta)
- activeresource (= 3.1.0.beta)
- activesupport (= 3.1.0.beta)
- bundler (~> 1.0)
- railties (= 3.1.0.beta)
- railties (3.1.0.beta)
- actionpack (= 3.1.0.beta)
- activesupport (= 3.1.0.beta)
- rack-ssl (~> 1.3.2)
- rake (>= 0.8.7)
- thor (~> 0.14.4)
-
-GEM
- remote: http://rubygems.org/
- specs:
- ansi (1.2.4)
+ tzinfo (~> 0.3.27)
+ activeresource (3.1.0.beta1)
+ activemodel (= 3.1.0.beta1)
+ activesupport (= 3.1.0.beta1)
+ activesupport (3.1.0.beta1)
+ multi_json (~> 1.0)
+ addressable (2.2.5)
archive-tar-minitar (0.5.2)
arel (2.1.0)
bcrypt-ruby (2.1.4)
builder (3.0.0)
+ capybara (0.4.1.2)
+ celerity (>= 0.7.9)
+ culerity (>= 0.2.4)
+ mime-types (>= 1.16)
+ nokogiri (>= 1.3.3)
+ rack (>= 1.0.0)
+ rack-test (>= 0.5.4)
+ selenium-webdriver (>= 0.0.27)
+ xpath (~> 0.1.3)
+ capybara-firebug (0.0.5)
+ capybara (~> 0.4.1.2)
+ celerity (0.8.9)
+ childprocess (0.1.8)
+ ffi (~> 1.0.6)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.1.0)
columnize (0.3.2)
+ configuration (1.2.0)
+ cucumber (0.10.2)
+ builder (>= 2.1.2)
+ diff-lcs (>= 1.1.2)
+ gherkin (>= 2.3.5)
+ json (>= 1.4.6)
+ term-ansicolor (>= 1.0.5)
+ cucumber-rails (0.4.1)
+ cucumber (>= 0.10.1)
+ nokogiri (>= 1.4.4)
+ rack-test (>= 0.5.7)
+ culerity (0.2.15)
daemons (1.1.3)
+ database_cleaner (0.6.7)
+ diff-lcs (1.1.2)
+ em-hiredis (0.1.0)
+ hiredis (~> 0.3.0)
+ em-websocket (0.2.1)
+ addressable (>= 2.1.1)
+ eventmachine (>= 0.12.9)
erubis (2.7.0)
- eventmachine (0.12.10)
execjs (0.3.1)
multi_json (~> 1.0)
+ ffi (1.0.7)
+ rake (>= 0.8.7)
+ gherkin (2.3.7)
+ json (>= 1.4.6)
+ haml (3.1.1)
+ haml-rails (0.3.4)
+ actionpack (~> 3.0)
+ activesupport (~> 3.0)
+ haml (~> 3.0)
+ railties (~> 3.0)
hike (1.0.0)
+ hiredis (0.3.1)
i18n (0.6.0beta1)
json (1.5.1)
+ json_pure (1.5.1)
+ launchy (0.4.0)
+ configuration (>= 0.0.5)
+ rake (>= 0.8.1)
linecache19 (0.5.12)
ruby_core_source (>= 0.1.4)
mail (2.3.0)
@@ -77,6 +123,7 @@ GEM
mime-types (1.16)
multi_json (1.0.0)
mysql2 (0.3.2)
+ nokogiri (1.4.4)
polyglot (0.3.1)
rack (1.3.0.beta)
rack-cache (1.0.1)
@@ -87,7 +134,22 @@ GEM
rack
rack-test (0.6.0)
rack (>= 1.0)
+ rails (3.1.0.beta1)
+ actionmailer (= 3.1.0.beta1)
+ actionpack (= 3.1.0.beta1)
+ activerecord (= 3.1.0.beta1)
+ activeresource (= 3.1.0.beta1)
+ activesupport (= 3.1.0.beta1)
+ bundler (~> 1.0)
+ railties (= 3.1.0.beta1)
+ railties (3.1.0.beta1)
+ actionpack (= 3.1.0.beta1)
+ activesupport (= 3.1.0.beta1)
+ rack-ssl (~> 1.3.2)
+ rake (>= 0.8.7)
+ thor (~> 0.14.6)
rake (0.8.7)
+ redis (2.2.0)
ruby-debug-base19 (0.11.25)
columnize (>= 0.3.1)
linecache19 (>= 0.5.11)
@@ -98,11 +160,21 @@ GEM
ruby-debug-base19 (>= 0.11.19)
ruby_core_source (0.1.5)
archive-tar-minitar (>= 0.5.2)
+ rubyzip (0.9.4)
sass (3.1.1)
+ selenium-webdriver (0.2.0)
+ childprocess (>= 0.1.7)
+ ffi (>= 1.0.7)
+ json_pure
+ rubyzip
+ sinatra (1.2.6)
+ rack (~> 1.1)
+ tilt (< 2.0, >= 1.2.2)
sprockets (2.0.0.beta.2)
hike (~> 1.0)
rack (~> 1.0)
tilt (~> 1.0)
+ term-ansicolor (1.0.5)
thin (1.2.11)
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
@@ -111,22 +183,32 @@ GEM
tilt (1.3)
treetop (1.4.9)
polyglot (>= 0.3.1)
- turn (0.8.2)
- ansi (>= 1.2.2)
tzinfo (0.3.27)
uglifier (0.5.1)
execjs
json
+ xpath (0.1.4)
+ nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
+ capybara
+ capybara-firebug
coffee-script
+ cucumber-rails
+ database_cleaner
+ em-hiredis
+ em-websocket
+ eventmachine!
+ evergreen!
+ haml
+ haml-rails
mysql2
- rails!
+ rails (= 3.1.0.beta1)
+ redis
ruby-debug19
sass
thin
- turn
uglifier
View
2  Rakefile
@@ -4,4 +4,4 @@
require File.expand_path('../config/application', __FILE__)
-Mercury::Application.load_tasks
+Carmenta::Application.load_tasks
View
BIN  app/assets/images/carmenta/clippy.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/loading-dark.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/loading-light.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/editable/buttons.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/_expander.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/_pressed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/historypanel.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/insertcharacter.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/insertlink.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/insertmedia.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/inserttable.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/inspectorpanel.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/notespanel.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/objectspanel.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/preview.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/redo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/save.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/todospanel.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/carmenta/toolbar/primary/undo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  app/assets/images/rails.png
Deleted file not rendered
View
15 app/assets/javascripts/application.js
@@ -1,6 +1,9 @@
-// FIXME: Tell people that this is a manifest file, real code should go into discrete files
-// FIXME: Tell people how Sprockets and CoffeeScript works
-//
-//= require jquery
-//= require jquery_ujs
-//= require_tree .
+/*!
+ * This file includes other files. To add javascript please create new .js or
+ * .js.coffee files and require them here, do not add code to this file.
+ *
+ *= require_self
+ *= require vendor
+ *= require carmenta/carmenta_editor
+ *= require_tree .
+ *---------------------------------------------------------------------------*/
View
138 app/assets/javascripts/carmenta/carmenta_editor.js.coffee
@@ -0,0 +1,138 @@
+#= require_self
+#= require ./history_buffer
+#= require ./dialog
+#= require ./statusbar
+#= require ./palette
+#= require ./select
+#= require ./panel
+#= require ./modal
+#= require ./toolbar
+#= require ./toolbar.button
+#= require ./toolbar.button_group
+#= require ./toolbar.expander
+#= require_tree ./regions
+#= require ./config
+
+String::titleize = -> @[0].toUpperCase() + this.slice(1)
+
+class CarmentaEditor
+
+ constructor: (@options = {}) ->
+ throw "CarmentaEditor is unsupported in this client. Supported browsers are chrome 10+, firefix 4+, and safari 5+." unless Carmenta.supported
+ @initializeInterface()
+
+
+ initializeInterface: ->
+ @iframe = $('<iframe>', {class: 'carmenta-iframe', seamless: 'true', frameborder: '0', src: 'about:blank'})
+ @iframe.load => @initializeFrame()
+ @iframe.attr('src', @iframeSrc())
+ @iframe.appendTo('body')
+
+ @bindEvents()
+
+ @toolbar = new Carmenta.Toolbar(@options)
+ @statusbar = new Carmenta.Statusbar(@options)
+
+
+ initializeFrame: ->
+ try
+ return if @iframe.data('loaded')
+ @iframe.data('loaded', true)
+ @document = @iframe.get(0).contentWindow.document
+
+ @regions = @initializeRegions()
+ @finalizeInterface()
+
+ @iframe.css({visibility: 'visible'})
+ catch error
+ alert("CarmentaEditor failed to load: #{error}\n\nPlease try refreshing.")
+
+
+ initializeRegions: ->
+ @buildRegion($(region)) for region in $('.carmenta-region', @document)
+
+
+ buildRegion: (region) ->
+# try
+ type = region.data('type').titleize()
+ new Carmenta.Regions[type](region)
+# catch error
+# alert(error)
+# alert("Region type is malformed, no data-type provided, or \"#{type}\" is unknown.")
+
+
+ finalizeInterface: ->
+ Carmenta.hijackLinks(@document)
+ @resize()
+
+
+ bindEvents: ->
+ Carmenta.bind('initialize:frame', => setTimeout(@initializeFrame, 200))
+
+ $(window).resize => @resize()
+ window.onbeforeunload = Carmenta.beforeUnload
+
+
+ resize: ->
+ width = $(window).width()
+ height = $(window).height()
+ toolbarHeight = @toolbar.height()
+ statusbarHeight = @statusbar.height()
+
+ Carmenta.displayRect = {top: toolbarHeight, left: 0, width: width, height: height - statusbarHeight - toolbarHeight}
+
+ @iframe.css {
+ top: toolbarHeight,
+ width: width,
+ height: height - statusbarHeight - toolbarHeight
+ }
+
+
+ iframeSrc: ->
+ window.location.href.replace(/([http|https]:\/\/.[^\/]*)\/edit\/?(.*)/i, "$1/$2")
+
+
+
+# Carmenta static properties and utlity methods
+Carmenta =
+ Regions: {}
+
+ version: 1.0
+ # No IE because it doesn't follow the w3c standards for designMode
+ # TODO: using client detection, but should use feature detection
+ supported: document.getElementById && document.designMode && !$.browser.konqueror && !$.browser.msie
+ silent: false
+ debug: true
+
+
+ beforeUnload: ->
+ if Carmenta.changes && !Carmenta.silent
+ return "You have unsaved changes. Are you sure you want to leave without saving them first?"
+
+
+ hijackLinks: (document) ->
+ for link in $('a', document)
+ if (link.target == '' || link.target == '_self') and !$(link).closest('.carmenta-region').length
+ $(link).attr('target', '_top')
+
+
+ refresh: ->
+ Carmenta.trigger('refresh')
+
+
+ bind: (eventName, callback) ->
+ $(document).bind("carmenta:#{eventName}", callback)
+
+
+ trigger: (eventName, arguments...) ->
+ $(document).trigger("carmenta:#{eventName}", arguments)
+ Carmenta.log(eventName, arguments)
+
+
+ log: ->
+ if Carmenta.debug && console
+ try console.debug(arguments) catch e
+
+
+ preventer: (event) ->
+ event.preventDefault()
View
182 app/assets/javascripts/carmenta/config.js.coffee
@@ -0,0 +1,182 @@
+Carmenta.config =
+
+ # Ignored Links
+ #
+ # Links need to be specially handled because the editor loads content into an
+ # iframe, and to ensure that links load outsite of the content iframe they're
+ # "hijacked" to load in the _top window. This allow for displaying a
+ # confirmation when leaving an edited page. There are times when you may be
+ # observing clicks on anchor tags and you might not want this behavior, for
+ # instance a link that pops a modal. You can add classnames to this array
+ # and the special handling won't be attached to anchors that have them.
+ #
+ ignoredLinks: ['lightview'],
+
+ # Toolbars
+ #
+ # This is where you can customize the toolbar by adding new ones, and add or
+ # change buttons and their behaviors. Any top level object put here will
+ # create a new toolbar. Buttons are nested inside the toolbars.
+ #
+ # Buttons can be grouped. A button group is simply a way to wrap buttons
+ # for styling. For instance, if you want to have them wrap as a group in the
+ # toolbar.
+ #
+ # It's important to note that each of the names (keys), in this object must
+ # be unique, regardless of if it's in a button group, or nested, etc.
+ #
+ # Button format: [label, description, {type: action, type: action, etc}]
+ # The available button types are:
+ #
+ # button: (default) calls handleCommand and passes the key of the object
+ # (eg. save, preview, undo etc.)
+ # toggle: toggles on or off when clicked, otherwise behaves like a button
+ # modal: opens a modal window, expects the action to be one of:
+ # a string url
+ # a function that returns a string url
+ # panel: opens a panel dialog, expects the action to be one of:
+ # a string url
+ # a function that returns a string url
+ # palette: opens a palette window, expects the action to be one of:
+ # a string url
+ # a function that returns a string url
+ # select: opens a pulldown style window, expects the action to be one of:
+ # a string url
+ # a function that returns a string url
+ # context: calls a callback function, expects the action to be:
+ # a function that returns a boolean to highlight the button
+ # note: if a function isn't provided, the key will be passed to
+ # the contextHandler (eg. backcolor, bold), in which case
+ # default context will be used (for more info read the
+ # Contexts section below)
+ # mode: toggle a given mode in the editor, expects the action to be:
+ # a string, denoting the name of the mode
+ # note: it's assumed that when a specific mode is turned on, all
+ # other modes will be turned off which happens automatically,
+ # thus putting the editor into a specific "state"
+ # preload: preloads views when the editor is loaded instead of on first open
+ # (only used for panels, selects, and palettes, otherwise ignored)
+ #
+ # Separators are any "button" that's not an array, and are expected to be a string. You can use
+ # two different separator styles: line, and spacer.
+ # '-' = line
+ # ' ' = spacer
+ #
+ toolbars:
+ primary:
+ save: ['Save', 'Save this page']
+ preview: ['Preview', 'Preview this page', {toggle: true, mode: true}]
+ sep1: ' '
+ undoredo:
+ undo: ['Undo', 'Undo your last action']
+ redo: ['Redo', 'Redo your last action']
+ sep: ' '
+ insertlink: ['Link', 'Insert Link', {modal: '/carmenta/modals/link'}]
+ insertmedia: ['Media', 'Insert Media (images and videos)', {modal: '/carmenta/modals/media'}]
+ inserttable: ['Table', 'Insert Table', {modal: '/carmenta/modals/table'}]
+ insertcharacter: ['Character', 'Special Characters', {modal: '/carmenta/modals/character'}]
+ objectspanel: ['Snippet', 'Snippet Panel', {panel: -> "/carmenta/panels/snippets"}]
+ sep2: ' '
+ historypanel: ['History', 'Page Version History', {panel: -> "/carmenta/panels/history"}]
+ sep3: ' '
+ notespanel: ['Notes', 'Page Notes', {panel: '/carmenta/panels/notes'}]
+ todospanel: ['Todos', 'Page Todos', {panel: '/carmenta/panels/todos'}]
+
+ editable:
+ predefined:
+ style: ['Style', null, {select: '/carmenta/selects/style', preload: true}]
+ sep1: ' '
+ formatblock: ['Block Format', null, {select: '/carmenta/selects/formatblock', preload: true}]
+ sep2: '-'
+ colors:
+ backcolor: ['Background Color', null, {palette: '/carmenta/palettes/backcolor', context: true, preload: true}]
+ sep1: ' '
+ forecolor: ['Text Color', null, {palette: '/carmenta/palettes/forecolor', context: true, preload: true}]
+ sep2: '-'
+ decoration:
+ bold: ['Bold', null, {context: true}]
+ italic: ['Italicize', null, {context: true}]
+ overline: ['Overline', null, {context: true}]
+ strikethrough: ['Strikethrough', null, {context: true}]
+ underline: ['Underline', null, {context: true}]
+ sep: '-'
+ script:
+ subscript: ['Subscript', null, {context: true}]
+ superscript: ['Superscript', null, {context: true}]
+ sep: '-'
+ justify:
+ justifyleft: ['Align Left', null, {context: true}]
+ justifycenter: ['Center', null, {context: true}]
+ justifyright: ['Align Right', null, {context: true}]
+ justifyfull: ['Justify Full', null, {context: true}]
+ sep: '-'
+ list:
+ insertunorderedlist: ['Unordered List', null, {context: true}]
+ insertorderedlist: ['Numbered List', null, {context: true}]
+ sep: '-'
+ indent:
+ outdent: ['Decrease Indentation', null]
+ indent: ['Increase Indentation', null]
+ sep: '-'
+ table:
+ _context: true
+ insertrowbefore: ['Insert Table Row', 'Insert a table row before the cursor']
+ insertrowafter: ['Insert Table Row', 'Insert a table row after the cursor']
+ deleterow: ['Delete Table Row', 'Delete this table row the cursor']
+ insertcolumnbefore: ['Insert Table Column', 'Insert a table column before the cursor']
+ insertcolumnafter: ['Insert Table Column', 'Insert a table column after the cursor']
+ deletecolumn: ['Delete Table Column', 'Delete this table column the cursor']
+ sep: '-'
+ rules:
+ horizontalrule: ['Horizontal Rule', 'Insert a horizontal rule']
+ sep: '-'
+ formatting:
+ removeformatting: ['Remove Formatting', 'Remove formatting for the selection']
+ sep: ' '
+ editors:
+ htmleditor: ['Edit HTML', 'Edit the HTML content'] # example behavior below
+
+ # Behaviors
+ #
+ # Behaviors are used to change the default behaviors of a given region type
+ # when a given button is clicked. For example, you may prefer to add HR tags
+ # using an HR wrapped within a div with a classname (for styling). To add
+ # your own complex behaviors you can do so here.
+ #
+ # You can see how the behavior matches up directly with the button name.
+ # It's also important to note that the callback functions are executed within
+ # the scope of the given region (so you can access private methods).
+ #
+ # You can add complex functionality to the html region for instance by adding
+ # a new button, called buynowbutton, and providing a behavior something like
+ # the following:
+ #
+ # New Button
+ # buynowbutton: ['Buy Now', 'Insert Buy Now Button']
+ #
+ # New Behavior
+ # buynowbutton: {insertHTML: '<a href="/buy-now" class="buy-now">Buy Now!</a>'}
+ #
+ behaviors:
+ horizontalrule: {insertHTML: '<hr/>'}
+ htmleditor:
+ call: ->
+ Carmenta.modal '/carmenta/modals/htmleditor.html', {
+ title: 'HTML Editor',
+ fullHeight: true,
+ afterLoad: => $('midas_html_editor_content').value = this.getContents();
+ }
+
+ # Contexts
+ #
+ # Contexts are used callback functions used for highlighting and
+ # disabling/enabling buttons and buttongroups. When the cursor enters an
+ # element within an html region for instance we want to disable or highlight
+ # buttons based on the properties of the given node.
+ #
+ # You can see some examples of contexts in:
+ #
+ # Carmenta.Toolbar.Button.contexts
+ # and
+ # Carmenta.Toolbar.ButtonGroup.contexts
+ #
View
97 app/assets/javascripts/carmenta/dialog.js.coffee
@@ -0,0 +1,97 @@
+class Carmenta.Dialog
+
+ constructor: (@url, @name, @options = {}) ->
+ @button = @options.for
+
+ @build()
+ @bindEvents()
+ @preload()
+
+
+ build: ->
+ @element = $('<div>', {class: "carmenta-dialog carmenta-#{@name}-dialog loading", style: 'display:none'})
+ @element.appendTo(@options.appendTo)
+
+
+ bindEvents: ->
+ @element.mousedown (event) -> event.stopPropagation()
+
+
+ preload: ->
+ @load() if @options.preload
+
+
+ toggle: (element) ->
+ if @visible then @hide() else @show()
+
+
+ resize: ->
+ @show()
+
+
+ show: ->
+ Carmenta.trigger('hide:dialogs', @)
+ @visible = true
+ if @loaded
+ @element.css({width: 'auto', height: 'auto'})
+ @position(@visible)
+ @appear()
+ else
+ @position()
+ @appear()
+
+
+ position: (keepVisible) ->
+
+
+ appear: ->
+ @element.css({display: 'block', opacity: 0})
+ @element.animate {opacity: .95}, 200, 'easeInOutSine', =>
+ @load(=> @resize()) unless @loaded
+
+
+ hide: ->
+ @element.hide()
+ @visible = false
+
+
+ load: (callback) ->
+ return unless @url
+ $.ajax @url, {
+ success: (data) =>
+ @loadContent(data)
+ callback() if callback
+
+# todo: this needs a better structure so it can be coffeescript
+# this.setupFunction = window['midas_setup_' + this.name];
+# if (this.setupFunction) this.setupFunction.call(this);
+
+
+ error: =>
+ @hide()
+ @button.removeClass('pressed')
+ alert("Carmenta was unable to load #{@url} for the #{@name} dialog.")
+ }
+
+
+ loadContent: (data) ->
+ @loaded = true
+ @element.removeClass('loading')
+ @element.html(data)
+
+# todo: this needs a better architecture -- listening to events should be considered, part of the above todo
+# show: function() {
+# if (this.toolbar.activeRegion) {
+# this.contextClass = this.toolbar.activeRegion.name;
+# this.element.addClassName(this.contextClass);
+# }
+# },
+# hide: function() {
+# if (this.contextClass) {
+# this.element.removeClassName(this.contextClass);
+# this.contextClass = null;
+# }
+# },
+# execute: function(action, options, event) {
+# Midas.fire('button', {action: this.name, event: event, toolbar: this.toolbar, options: options});
+# },
View
0  vendor/assets/stylesheets/.gitkeep → ...scripts/carmenta/dialogs/common_dialogs.js.coffee
File renamed without changes
View
5 app/assets/javascripts/carmenta/history_buffer.js.coffee
@@ -0,0 +1,5 @@
+class HistoryBuffer extends Array
+
+ constructor: ->
+ @push(arguments)
+
View
145 app/assets/javascripts/carmenta/modal.js.coffee
@@ -0,0 +1,145 @@
+Carmenta.modal = (url, options) ->
+ Carmenta.modal.show(url, options)
+ return Carmenta.modal
+
+$.extend Carmenta.modal, {
+
+ minWidth: 400
+
+ show: (@url, @options = {}) ->
+ @initialize()
+ if @visible then @update() else @appear()
+
+
+ initialize: ->
+ return if @initialized
+ @build()
+ @bindEvents()
+ @initialized = true
+
+
+ build: ->
+ @element = $('<div>', {class: 'carmenta-modal loading'})
+ @element.html('<h1 class="carmenta-modal-title"><span></span><a>&times;</a></h1><div class="carmenta-modal-content-container"><div class="carmenta-modal-content"></div></div>');
+
+ @overlay = $('<div>', {class: 'carmenta-modal-overlay'})
+
+ @titleElement = @element.find('.carmenta-modal-title')
+ @contentContainerElement = @element.find('.carmenta-modal-content-container')
+ @contentElement = @element.find('.carmenta-modal-content')
+
+ @element.appendTo(@options.appendTo || 'body')
+ @overlay.appendTo(@options.appendTo || 'body')
+
+ @titleElement.find('span').html(@options.title)
+
+
+ bindEvents: ->
+ Carmenta.bind 'refresh', => @resize(true)
+
+ $(window).resize => @position()
+
+ @overlay.click => @hide()
+
+ @titleElement.find('a').click => @hide()
+ @titleElement.mousedown(Carmenta.preventer)
+
+
+ appear: ->
+ @position()
+
+ @overlay.show()
+ @overlay.animate {opacity: 1}, 200, 'easeInOutSine', =>
+ @element.css({top: -@element.height()})
+ @setTitle()
+ @element.show()
+ @element.animate {top: 0}, 200, 'easeInOutSine', =>
+ @visible = true
+ @load()
+
+
+ position: ->
+ viewportWidth = $(window).width()
+ viewportHeight = $(window).height()
+
+ @contentElement.css({height: 'auto'})
+ @element.css({width: 'auto', height: 'auto', display: 'block', visibility: 'hidden'})
+
+ width = @element.width()
+ height = @element.height()
+
+ width = @minWidth if width < @minWidth
+ height = viewportHeight - 20 if height > viewportHeight - 20
+
+ @contentElement.css({height: height - @titleElement.outerHeight()})
+
+ @element.css {
+ left: (viewportWidth - width) / 2
+ width: width,
+ height: height,
+ display: if @visible then 'block' else 'none',
+ visibility: 'visible'
+ }
+
+
+ resize: (keepVisible) ->
+ visibility = if keepVisible then 'visible' else 'hidden'
+ @contentElement.css({height: 'auto', visibility: visibility, display: 'block'})
+
+ viewportHeight = $(window).height()
+ titleHeight = @titleElement.outerHeight()
+
+ width = @contentElement.outerWidth()
+ height = @contentElement.outerHeight() + titleHeight
+
+ width = @minWidth if width < @minWidth
+ height = viewportHeight - 20 if height > viewportHeight - 20
+
+ @element.stop().animate {left: ($(window).width() - width) / 2, width: width, height: height}, 200, 'easeInOutSine', =>
+ @contentElement.css({height: height - titleHeight, visibility: 'visible', display: 'block'})
+
+
+ update: ->
+ @reset()
+ @resize()
+ @load()
+
+
+ load: ->
+ @element.addClass('loading')
+ @setTitle()
+ $.ajax @url, {
+ success: (data) => @loadContent(data)
+ error: =>
+ @hide()
+ alert("Carmenta was unable to load #{@url} for the modal.")
+ }
+
+
+ loadContent: (data, options) ->
+ @options = options || @options
+ @setTitle()
+ @loaded = true
+ @element.removeClass('loading')
+ @contentElement.html(data)
+ @contentElement.css({display: 'none', visibility: 'hidden'})
+ @resize()
+
+
+ setTitle: ->
+ @titleElement.find('span').html(@options.title)
+
+
+ reset: ->
+ @titleElement.find('span').html('')
+ @contentElement.html('')
+
+
+ hide: ->
+ @element.hide()
+ @overlay.hide()
+ @reset()
+
+ @visible = false
+
+}
View
0  app/assets/javascripts/carmenta/modals/common_modals.js.coffee
No changes.
View
29 app/assets/javascripts/carmenta/palette.js.coffee
@@ -0,0 +1,29 @@
+class Carmenta.Palette extends Carmenta.Dialog
+
+ constructor: (@url, @name, @options = {}) ->
+ super
+
+
+ build: ->
+ @element = $('<div>', {class: "carmenta-palette carmenta-#{@name}-palette loading", style: 'display:none'})
+ @element.appendTo(@options.appendTo)
+
+
+ bindEvents: ->
+ Carmenta.bind('hide:dialogs', (event, dialog) => @hide() unless dialog == @)
+ super
+
+
+ position: (keepVisible) ->
+ @element.css({top: 0, left: 0, display: 'block', visibility: 'hidden'})
+ position = @button.offset()
+ width = @element.width()
+
+ position.left = position.left - width + @button.width() if position.left + width > $(window).width()
+
+ @element.css {
+ top: position.top + @button.height(),
+ left: position.left,
+ display: if keepVisible then 'block' else 'none',
+ visibility: 'visible'
+ }
View
98 app/assets/javascripts/carmenta/panel.js.coffee
@@ -0,0 +1,98 @@
+class Carmenta.Panel extends Carmenta.Dialog
+
+ constructor: (@url, @name, @options) ->
+ super
+
+
+ build: ->
+ @element = $('<div>', {class: 'carmenta-panel loading', style: 'display:none;'})
+ @titleElement = $("<h1>#{@options.title}</h1>").appendTo(@element)
+ @paneElement = $('<div>', {class: 'carmenta-panel-pane'}).appendTo(@element)
+
+ @element.appendTo(@options.appendTo || 'body');
+
+
+ bindEvents: ->
+ $(window).resize => @position(@visible)
+
+ @element.mousedown (event) -> event.stopPropagation()
+
+ Carmenta.bind 'hide:panels', (event, panel) =>
+ unless panel == @
+ @button.removeClass('pressed')
+ @hide()
+
+ super
+
+
+ show: ->
+ Carmenta.trigger('hide:panels', @)
+ super
+
+
+ resize: ->
+ @paneElement.css({display: 'none'})
+ preWidth = @element.width()
+
+ @paneElement.css({visibility: 'hidden', width: 'auto', display: 'block'})
+ postWidth = @element.width()
+
+ @paneElement.css({visibility: 'visible', display: 'none'})
+ position = @element.offset()
+ @element.animate {left: position.left - (postWidth - preWidth), width: postWidth}, 200, 'easeInOutSine', =>
+ @paneElement.css({display: 'block', width: postWidth})
+ @makeDraggable()
+
+ @hide() unless @visible
+
+
+ position: (keepVisible) ->
+ @element.css({display: 'block', visibility: 'hidden'})
+ offset = @element.offset()
+ elementWidth = @element.width()
+ height = Carmenta.displayRect.height - 16
+
+ paneHeight = height - @titleElement.outerHeight()
+ @paneElement.css({height: paneHeight, overflow: if paneHeight < 30 then 'hidden' else 'auto'})
+
+ left = Carmenta.displayRect.width - elementWidth - 20 unless @moved
+ left = 8 if left <= 8
+
+ if @pinned || elementWidth + offset.left > Carmenta.displayRect.width - 20
+ left = Carmenta.displayRect.width - elementWidth - 20
+
+ @element.css {
+ top: Carmenta.displayRect.top + 8,
+ left: left,
+ height: height,
+ display: if keepVisible then 'block' else 'none',
+ visibility: 'visible'
+ }
+
+ @makeDraggable()
+ @element.hide() unless keepVisible
+
+
+ loadContent: (data) ->
+ @loaded = true
+ @element.removeClass('loading')
+ @paneElement.css({visibility: 'hidden'})
+ @paneElement.html(data)
+
+
+ makeDraggable: ->
+ elementWidth = @element.width()
+ @draggable = @element.draggable {
+ handle: 'h1',
+ axis: 'x',
+ opacity: 0.70
+ scroll: false,
+ addClasses: false,
+ iframeFix: true,
+ containment: [8, 0, Carmenta.displayRect.width - elementWidth - 20, 0] #[x1, y1, x2, y2]
+ stop: =>
+ left = @element.offset().left
+ @moved = true
+ @pinned = if left > Carmenta.displayRect.width - elementWidth - 30 then true else false
+ return true
+ }
View
31 app/assets/javascripts/carmenta/regions/editable.js.coffee
@@ -0,0 +1,31 @@
+class Carmenta.Regions.Editable
+# type = 'editable'
+
+ constructor: (@element, @options = {}) ->
+ Carmenta.log('making editable', @element, @options)
+
+ @document = @options
+ @history = new HistoryBuffer()
+ @build()
+
+
+ build: ->
+ @element.addClass('carmenta-region')
+
+ # set some initial content to so mozilla works correctly
+ @html('&nbsp;') if $.browser.mozilla && @html() == ''
+
+ if @options.inline
+ @element.css({height: 'auto', minHeight: '20px', minWidth: '20px'})
+ else
+ width = @element.scrollWidth
+ @element.css({overflow: 'auto'}) unless @element.css('overflow') == 'hidden'
+ @element.css({maxWidth: width}) if width
+
+ @element.get(0).contentEditable = true
+
+# this.doc.execCommand('styleWithCSS', false, false);
+# this.doc.execCommand('enableInlineTableEditing', false, false);
+
+ html: (value = null) ->
+ if value then @element.html(value) else @element.html().replace(/^\s+|\s+$/g, '')
View
7 app/assets/javascripts/carmenta/regions/snippet.js.coffee
@@ -0,0 +1,7 @@
+class Carmenta.Regions.Snippet
+ type = 'snippet'
+
+ constructor: (@element) ->
+ Carmenta.log('making snippetable', @element)
+
+ @history = new HistoryBuffer()
View
40 app/assets/javascripts/carmenta/select.js.coffee
@@ -0,0 +1,40 @@
+class Carmenta.Select extends Carmenta.Dialog
+
+ constructor: (@url, @name, @options) ->
+ super
+
+
+ build: ->
+ @element = $('<div>', {class: "carmenta-select carmenta-#{@name}-select loading", style: 'display:none'})
+ @element.appendTo(@options.appendTo)
+
+
+ bindEvents: ->
+ Carmenta.bind('hide:dialogs', (event, dialog) => @hide() unless dialog == @)
+ super
+
+
+ position: (keepVisible) ->
+ @element.css({top: 0, left: 0, display: 'block', visibility: 'hidden'})
+ position = @button.offset()
+ elementWidth = @element.width()
+ elementHeight = @element.height()
+ documentHeight = $(document).height()
+
+ top = position.top + (@button.height() / 2) - (elementHeight / 2)
+ top = position.top - 100 if top < position.top - 100
+ top = 20 if top < 20
+
+ height = if @loaded then 'auto' else elementHeight
+ height = documentHeight - top - 20 if top + elementHeight >= documentHeight - 20
+
+ left = position.left
+ left = left - elementWidth + @button.width() if left + elementWidth > $(window).width()
+
+ @element.css {
+ top: top,
+ left: left,
+ height: height,
+ display: if keepVisible then 'block' else 'none',
+ visibility: 'visible'
+ }
View
17 app/assets/javascripts/carmenta/statusbar.js.coffee
@@ -0,0 +1,17 @@
+class Carmenta.Statusbar
+
+ constructor: (@options) ->
+ @build()
+ @bindEvents()
+
+
+ build: ->
+ @element = $('<div>', {class: 'carmenta-statusbar'}).appendTo('body')
+
+
+ bindEvents: ->
+ @element.mousedown(Carmenta.preventer)
+
+
+ height: ->
+ @element.outerHeight()
View
126 app/assets/javascripts/carmenta/toolbar.button.js.coffee
@@ -0,0 +1,126 @@
+class Carmenta.Toolbar.Button
+
+ constructor: (@name, @title, @summary = null, @handled = [], @toolbar) ->
+ @build()
+ @bindEvents()
+ return @element
+
+
+ build: ->
+ @element = $('<div>', {title: @summary ? @title, class: "carmenta-button carmenta-#{@name}-button"})
+ @element.html("<em>#{@title}</em>")
+ @element.data('expander', "<div class=\"carmenta-expander-button\" data-button=\"#{@name}\"><em></em><span>#{@title}</span></div>")
+
+ dialogOptions = {title: @summary || @title, preload: @handled.preload, appendTo: @toolbar.element, for: @element}
+ for type, mixed of @handled
+ switch type
+
+ when 'preload' then true
+
+ when 'toggle'
+ @handled[type] = true
+
+ when 'mode'
+ @handled[type] = if mixed == true then @name else mixed
+
+ when 'context'
+ @handled[type] = if $.isFunction(mixed) then mixed else Carmenta.Toolbar.Button.contexts[@name]
+
+ when 'palette'
+ @element.addClass("carmenta-button-palette")
+ url = if $.isFunction(mixed) then mixed.call(@, @name) else mixed
+ @handled[type] = new Carmenta.Palette(url, @name, dialogOptions)
+
+ when 'select'
+ @element.addClass("carmenta-button-select").find('em').html(@title)
+ url = if $.isFunction(mixed) then mixed.call(@, @name) else mixed
+ @handled[type] = new Carmenta.Select(url, @name, dialogOptions)
+
+ when 'panel'
+ @element.addClass('carmenta-button-panel')
+ url = if $.isFunction(mixed) then mixed.call(@, @name) else mixed
+ @handled['toggle'] = true
+ @handled[type] = new Carmenta.Panel(url, @name, dialogOptions)
+
+ when 'modal'
+ @handled[type] = if $.isFunction(mixed) then mixed.apply(@, @name) else mixed
+
+ else throw "Unknown button type #{type} used for the #{@name} button"
+
+
+ bindEvents: ->
+ @element.click (event) =>
+ if @element.closest('.disabled').length then return
+
+ handled = false
+ for type, mixed of @handled
+ switch type
+
+ when 'toggle'
+ @togglePressed()
+
+ when 'mode'
+ handled = true
+ Carmenta.trigger('mode', {mode: mixed})
+
+ when 'modal'
+ handled = true
+ Carmenta.modal(@handled['modal'], {title: @summary || @title})
+
+ when 'palette', 'select', 'panel'
+ event.stopPropagation()
+ handled = true
+ @handled[type].toggle()
+
+ Carmenta.trigger('button', {action: @name}) unless handled
+
+
+ togglePressed: ->
+ @element.toggleClass('pressed')
+
+
+
+# Button contexts
+Carmenta.Toolbar.Button.contexts =
+ backcolor: (node) ->
+ @element.css('background-color', node.css('background-color'))
+
+ forecolor: (node) ->
+ @element.css('background-color', node.css('color'))
+
+ bold: (node) ->
+ weight = node.css('font-weight')
+ weight == 'bold' || weight > 400
+
+ italic: (node) ->
+ node.css('font-style') == 'italic'
+
+ strikethrough: (node) ->
+ node.css('text-decoration') == 'line-through'
+
+ underline: (node) ->
+ node.css('text-decoration') == 'underline'
+
+ subscript: (node) ->
+ node.closest('sub').length > 0
+
+ superscript: (node) ->
+ node.closest('sup').length > 0
+
+ justifyleft: (node) ->
+ node.css('text-align').indexOf('left') > -1
+
+ justifycenter: (node) ->
+ node.css('text-align').indexOf('center') > -1
+
+ justifyright: (node) ->
+ node.css('text-align').indexOf('right') > -1
+
+ justifyfull: (node) ->
+ node.css('text-align').indexOf('justify') > -1
+
+ insertorderedlist: (node, region) ->
+ node.closest('ol', region.element).length > 0
+
+ insertunorderedlist: (node, region) ->
+ node.closest('ul', region.element).length > 0
View
18 app/assets/javascripts/carmenta/toolbar.button_group.js.coffee
@@ -0,0 +1,18 @@
+class Carmenta.Toolbar.ButtonGroup
+
+ constructor: (@name, @options) ->
+ @build()
+ return @element
+
+
+ build: ->
+ @element = $('<div>', {class: "carmenta-button-group carmenta-#{@name}-group"})
+ if @options._context
+ @element.addClass('disabled')
+
+
+
+# ButtonGroup contexts
+Carmenta.Toolbar.ButtonGroup.contexts =
+ table: (node, region) ->
+ node.closest('table', region).length > 0
View
58 app/assets/javascripts/carmenta/toolbar.expander.js.coffee
@@ -0,0 +1,58 @@
+class Carmenta.Toolbar.Expander extends Carmenta.Palette
+
+ constructor: (@name, @options = {}) ->
+ @container = @options.for
+ @containerWidth = @container.outerWidth()
+ super(null, @name, @options)
+
+ return @element
+
+
+ build: ->
+ @container.css({whiteSpace: 'normal'})
+ @trigger = $('<div>', {class: 'carmenta-toolbar-expander'}).appendTo(@options.appendTo)
+ @element = $('<div>', {class: "carmenta-palette carmenta-expander carmenta-#{@name}-expander", style: 'display:none'})
+ @windowResize()
+
+
+ bindEvents: ->
+ Carmenta.bind('hide:dialogs', (event, dialog) => @hide() unless dialog == @)
+
+ super
+
+ $(window).resize => @windowResize()
+
+ @trigger.click (event) =>
+ event.stopPropagation()
+ hiddenButtons = []
+ for button in @container.find('.carmenta-button')
+ button = $(button)
+ hiddenButtons.push(button.data('expander')) if button.offset().top > 5
+
+ @loadContent(hiddenButtons.join(''))
+ @toggle()
+
+ @element.click (event) =>
+ buttonName = $(event.target).closest('[data-button]').data('button')
+ button = @container.find(".carmenta-#{buttonName}-button")
+ button.click()
+
+
+ windowResize: ->
+ if @containerWidth > $(window).width() then @trigger.show() else @trigger.hide()
+ @hide()
+
+
+ position: (keepVisible) ->
+ @element.css({top: 0, left: 0, display: 'block', visibility: 'hidden'})
+ position = @trigger.offset()
+ width = @element.width()
+
+ position.left = position.left - width + @trigger.width() if position.left + width > $(window).width()
+
+ @element.css {
+ top: position.top + @trigger.height(),
+ left: position.left,
+ display: if keepVisible then 'block' else 'none',
+ visibility: 'visible'
+ }
View
67 app/assets/javascripts/carmenta/toolbar.js.coffee
@@ -0,0 +1,67 @@
+class Carmenta.Toolbar
+
+ constructor: (@options = {}) ->
+ @build()
+ @bindEvents()
+ @resize()
+
+
+ build: ->
+ @element = $('<div>', {class: 'carmenta-toolbar-container', style: 'width:10000px'}).appendTo($(@options.appendTo).get(0) ? 'body')
+
+ for toolbarName, buttons of Carmenta.config.toolbars
+ toolbar = $('<div>', {class: "carmenta-toolbar carmenta-#{toolbarName}-toolbar"}).appendTo(@element)
+ container = $('<div>', {class: 'carmenta-toolbar-button-container'}).appendTo(toolbar)
+
+ for buttonName, options of buttons
+ @buildButton(buttonName, options).appendTo(container)
+
+ if container.css('white-space') == 'nowrap'
+ expander = new Carmenta.Toolbar.Expander(toolbarName, {appendTo: toolbar, for: container})
+ expander.appendTo(@element)
+
+ @element.css({width: '100%'})
+
+ buildButton: (name, options) ->
+ switch $.type(options)
+
+ when 'array' # button
+ [title, summary, handled] = options
+ new Carmenta.Toolbar.Button(name, title, summary, handled, @)
+
+ when 'object' # button group
+ group = new Carmenta.Toolbar.ButtonGroup(name, options)
+ for a, o of options
+ @buildButton(a, o).appendTo(group) unless a == '_context'
+ group
+
+ when 'string' # separator
+ $('<hr>', {class: "carmenta-#{if options == '-' then 'line-separator' else 'separator'}"})
+
+ else throw "Unknown button structure -- please provide an array, object, or string for #{name}."
+
+
+ bindEvents: ->
+ $(window).resize => @resize()
+
+ @element.mousedown(Carmenta.preventer)
+
+ @element.click ->
+ Carmenta.trigger('hide:dialogs')
+
+
+
+ resize: ->
+
+
+ height: ->
+ @element.outerHeight()
+
+
+ disable: ->
+ # disable the entire toolbar
+ # disable a specific toolbar
+ # disable specific buttons or button groups
+
+
+ enable: ->
View
34 app/assets/javascripts/carmenta/websocket.js.coffee
@@ -0,0 +1,34 @@
+Carmenta.websocket =
+
+ websocket: $.websocket("ws://#{$.uri(window.location.href).host}:8081")
+
+
+ send: (eventName, options) ->
+ package = {}
+ package[eventName] = options
+ @websocket.send(package)
+
+
+ bind: (eventName, callback) ->
+ # todo: this will override any that are already set -- callbacks should be an array that we can push onto
+ $.websocketSettings[eventName] = callback
+
+#window.socket = $.websocket(, {
+# lock: (element) ->
+# $('#' + element).attr('disabled', true);
+#
+# unlock: (element) ->
+# $('#' + element).attr('disabled', false);
+#
+# chat: (element) ->
+# $('#chat').get(0).innerHTML += message + "<br/>";
+#});
+#
+#$(document).ready ->
+#
+# $('.shared').bind 'focus', -> window.socket.send({"lock": this.id})
+#
+# $('.shared').bind 'blur', -> window.socket.send({"unlock": this.id})
+#
+# $('.shared').bind 'keypress', (e) ->
+# window.socket.send({chat: $(this).val()}) if (e.charCode == 13)
View
10 app/assets/javascripts/vendor.js
@@ -0,0 +1,10 @@
+/*
+ *= require jquery-1.6
+ *= require jquery-ui-1.8.12.custom.min
+ *= require jquery.cookie
+ *= require jquery.easing
+ *= require jquery.json2
+ *= require jquery.ujs
+ *= require jquery.uri
+ *= require jquery.websocket
+ */
View
8 app/assets/stylesheets/application.css
@@ -1,5 +1,7 @@
/*
- * FIXME: Introduce SCSS & Sprockets
+ * This file includes other files. To add styles please create new .css or
+ * .scss files and require them here, do not add styles to this file.
+ *
*= require_self
- *= require_tree .
-*/
+ *= require_tree .
+ */
View
15 app/assets/stylesheets/carmenta/carmenta_editor.scss
@@ -0,0 +1,15 @@
+html, body {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ overflow: hidden;
+}
+
+.carmenta-iframe {
+ visibility: hidden;
+ width: 100%;
+ position: absolute;
+ top: 100px;
+}
View
136 app/assets/stylesheets/carmenta/dialog.scss
@@ -0,0 +1,136 @@
+/* Dialog
+ *----------------------------------------------------------------------------*/
+.carmenta-dialog,
+.carmenta-select,
+.carmenta-palette {
+ position: absolute;
+ z-index: 10012;
+ width: 30px;
+ height: 30px;
+ border: 1px solid #727272;
+ border-radius: 2px;
+ -moz-border-radius: 2px;
+ margin-top: -1px;
+ background-color: #E2E1E2;
+ box-shadow: 1px 1px 4px rgba(0,0,0, .5);
+ -moz-box-shadow: 1px 1px 4px rgba(0,0,0, .5);
+ font-family: Helvetica, Tahoma, Arial, sans-serif;
+ font-size: 8.5pt;
+ &.loading {
+ background-image: url(/assets/carmenta/loading-light.gif);
+ background-repeat: no-repeat;
+ background-position: center;
+ }
+}
+
+
+/* Select
+ *----------------------------------------------------------------------------*/
+.carmenta-select {
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ overflow: auto;
+ background-color: #FFF;
+}
+
+
+/* Panel
+ *----------------------------------------------------------------------------*/
+.carmenta-panel {
+ position: absolute;
+ z-index: 10011;
+ background-color: #111;
+ opacity: .9;
+ box-shadow: 1px 1px 4px rgba(0,0,0, .5);
+ -moz-box-shadow: 1px 1px 4px rgba(0,0,0, .5);
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ color: #FFF;
+ font-family: Helvetica, Tahoma, Arial, sans-serif;
+ font-size: 9.5pt;
+ max-width: 500px;
+ &.loading {
+ background-image: url(/assets/carmenta/loading-dark.gif);
+ background-repeat: no-repeat;
+ background-position: center;
+ }
+ h1,
+ h3 {
+ font-size: 9pt;
+ padding: 10px 15px 8px;
+ margin: 0;
+ background: #333;
+ white-space: nowrap;
+ }
+ h1 {
+ font-size: 10pt;
+ -moz-border-radius-topleft: 4px;
+ -moz-border-radius-topright: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ height: 15px;
+ cursor: move;
+ text-shadow: 1px 1px 2px rgba(0,0,0, .9);
+ }
+ .carmenta-panel-pane {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 15px;
+ overflow: auto;
+ width: 100%;
+ h3 {
+ margin: 10px -15px;
+ font-size: 9.5pt;
+ font-weight: normal;
+ padding: 8px 14px;
+ }
+ }
+}
+
+
+/* Specific dialogs (eg. color palettes, selects)
+ *----------------------------------------------------------------------------*/
+.carmenta-color-picker {
+ width: 170px;
+ height: auto;
+ padding: 1px;
+ .picker {
+ float: left;
+ width: 15px;
+ height: 15px;
+ margin: 1px;
+ cursor: default;
+ &:hover {
+ outline: 1px solid #333;
+ }
+ }
+ .last-picked {
+ position: relative;
+ top: 1px;
+ width: 166px;
+ border: 1px solid #333;
+ border-radius: 2px;
+ margin: 1px 1px 2px 1px;
+ -moz-border-radius: 2px;
+ clear: left;
+ text-align: center;
+ }
+}
+
+.carmenta-select-options {
+ margin: 10px 0;
+ white-space: nowrap;
+ * {
+ cursor: default;
+ padding: 0 10px;
+ margin: 0;
+ line-height: 1.6em;
+ }
+ *:hover {
+ background-color: #E2E1E2 !important;
+ color: #000 !important;
+ }
+ div[data-tag=pre] {
+ font-family: monospace;
+ }
+}
View
88 app/assets/stylesheets/carmenta/modal.scss
@@ -0,0 +1,88 @@
+/* Modal
+ *----------------------------------------------------------------------------*/
+.carmenta-modal-overlay {
+ position: absolute;
+ z-index: 10040;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ display: none;
+ background: rgba(0,0,0, .65);
+}
+
+.carmenta-modal {
+ position: absolute;
+ z-index: 10050;
+ top: 0;
+ width: 500px;
+ padding: 0 0 10px;
+ background: #EFEFEF;
+ -webkit-border-bottom-left-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ -moz-border-radius-bottomright: 4px;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ -moz-box-shadow: 0 0 40px rgba(0, 0, 0, .9);
+ box-shadow: 0 0 40px rgba(0, 0, 0, .9);
+ font: normal normal normal 12px/normal Helvetica, Tahoma, Arial, sans-serif;
+ &.loading .carmenta-modal-content-container {
+ background: #EFEFEF url(/assets/carmenta/loading-light.gif) no-repeat center;
+ }
+ h1.carmenta-modal-title {
+ margin: 0;
+ padding: 2px 10px 0 10px;
+ background: #DDD;
+ border-bottom: 1px solid #CCC;
+ white-space: nowrap;
+ font-size: 14px;
+ line-height: 23px;
+ overflow: hidden;
+ &:after {
+ content: '\00a0';
+ display: block;
+ visibility: hidden;
+ clear: both;
+ height: 0;
+ }
+ span {
+ color: #000;
+ text-shadow: #EEE 1px 1px 0;
+ }
+ a {
+ display: block;
+ float: right;
+ font-size: 10px;
+ cursor: pointer;
+ color: #666;
+ padding: 0 4px;
+ line-height: 23px;
+ &:hover {
+ color: #333;
+ }
+ }
+ }
+ .carmenta-modal-content-container {
+ float: left;
+ width: 100%;
+ }
+ .carmenta-modal-content {
+ overflow: auto;
+ float: left;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 20px 20px 10px;
+ font-family: Helvetica, Tahoma, Arial, sans-serif;
+ color: #000;
+ &:after {
+ display: block;
+ clear: both;
+ content: '\00a0';
+ visibility: hidden;
+ overflow: hidden;
+ height: 0;
+ }
+ }
+}
View
17 app/assets/stylesheets/carmenta/statusbar.scss
@@ -0,0 +1,17 @@
+/* Statusbar
+ *----------------------------------------------------------------------------*/
+.carmenta-statusbar {
+ position: absolute;
+ z-index: 10020;
+ bottom: 0;
+ width: 100%;
+ height: 12px;
+ cursor: default;
+ padding: 5px 10px 4px 10px;
+ background: #E2E1E2;
+ border-top: 1px solid #727272;
+ font-family: Helvetica, Tahoma, Arial, sans-serif;
+ font-size: 8.5pt;
+ line-height: 12px;
+ color: #222;
+}
View
267 app/assets/stylesheets/carmenta/toolbar.scss
@@ -0,0 +1,267 @@
+/* Toolbar
+ *----------------------------------------------------------------------------*/
+.carmenta-toolbar-container {
+ position: absolute;
+ z-index: 10010;
+ top: 0;
+ width: 100%;
+ border-bottom: 1px solid #E2E1E2;
+ .carmenta-toolbar {
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, rgb(198,198,198)), color-stop(1, rgb(226,225,226)));
+ background-image: -moz-linear-gradient(center bottom, rgb(198,198,198) 0%, rgb(226,225,226) 100%);
+ border-bottom: 1px solid #727272;
+ cursor: default;
+ }
+ .carmenta-toolbar-button-container {
+ float: left;
+ }
+ .carmenta-toolbar-expander {
+ position: absolute;
+ display: none;
+ right: 0;
+ border-left: 1px solid #727272;
+ }
+ .carmenta-button,
+ .carmenta-button-group,
+ .carmenta-separator,
+ .carmenta-line-separator {
+ display: block;
+ float: left;
+ }
+ .carmenta-separator,
+ .carmenta-line-separator {
+ width: 1px;
+ border: 0;
+ margin: 0;
+ }
+ .carmenta-line-separator {
+ width: 1px;
+ background: #727272;
+ }
+ .carmenta-button em {
+ display: block;
+ font-style: normal;
+ }
+ .carmenta-expander {
+ padding: 5px 0;
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ .carmenta-expander-button {
+ cursor: default;
+ white-space: nowrap;
+ padding: 0 20px 0 10px;
+ &:hover {
+ background: #CCC;
+ }
+ em {
+ display: inline-block;
+ float: left;
+ width: 20px;
+ height: 20px;
+ margin-right: 10px;
+ -webkit-background-size: 100% 100%;
+ -moz-background-size: 100% 100%;
+ background-size: 100% 100%;
+ }
+ span {
+ display: inline-block;
+ line-height: 20px;
+ }
+ }
+ }
+ .disabled .carmenta-button,
+ .carmenta-button.disabled {
+ opacity: 0.33;
+ }
+}
+
+
+/* Toolbar: Primary Toolbar
+ *----------------------------------------------------------------------------*/
+.carmenta-primary-toolbar {
+ position: relative;
+ height: 58px;
+ overflow: hidden;
+ text-shadow: #EEE 0 1px 0;
+ .carmenta-button {
+ display: inline-block;
+ height: 58px;
+ margin-bottom: 20px;
+ min-width: 50px;
+ text-align: center;
+ white-space: nowrap;
+ text-decoration: none;
+ font-family: Helvetica, Tahoma, Arial, sans-serif;
+ &.pressed {
+ background-image: url(/assets/carmenta/toolbar/primary/_pressed.png)
+ }
+ em {
+ margin: 0 -5px;
+ height: 15px;
+ padding-top: 41px;
+ background-repeat: no-repeat;
+ background-position: 50% 7px;
+ font-size: 8.5pt;
+ line-height: 15px;
+ color: #222;
+ }
+ }
+ .carmenta-separator,
+ .carmenta-line-separator {
+ display: inline-block;
+ width: 1px;
+ height: 50px;
+ margin: 5px 25px 28px;
+ }
+ .carmenta-toolbar-button-container {
+ white-space: nowrap;
+ padding-right: 10px;
+ }
+ .carmenta-toolbar-expander {
+ width: 12px;
+ height: 58px;
+ background: rgba(0, 0, 0, .2) url(/assets/carmenta/toolbar/primary/_expander.png) no-repeat center 90%;
+ }
+}
+/* default buttons */
+.carmenta-primary-toolbar .carmenta-save-button em,
+.carmenta-expander-button[data-button=save] em { background-image: url(/assets/carmenta/toolbar/primary/save.png) }
+.carmenta-primary-toolbar .carmenta-preview-button em,
+.carmenta-expander-button[data-button=preview] em { background-image: url(/assets/carmenta/toolbar/primary/preview.png) }
+.carmenta-primary-toolbar .carmenta-undo-button em,
+.carmenta-expander-button[data-button=undo] em { background-image: url(/assets/carmenta/toolbar/primary/undo.png) }
+.carmenta-primary-toolbar .carmenta-redo-button em,
+.carmenta-expander-button[data-button=redo] em { background-image: url(/assets/carmenta/toolbar/primary/redo.png) }
+.carmenta-primary-toolbar .carmenta-insertlink-button em,
+.carmenta-expander-button[data-button=insertlink] em { background-image: url(/assets/carmenta/toolbar/primary/insertlink.png) }
+.carmenta-primary-toolbar .carmenta-insertmedia-button em,
+.carmenta-expander-button[data-button=insertmedia] em { background-image: url(/assets/carmenta/toolbar/primary/insertmedia.png) }
+.carmenta-primary-toolbar .carmenta-inserttable-button em,
+.carmenta-expander-button[data-button=inserttable] em { background-image: url(/assets/carmenta/toolbar/primary/inserttable.png) }
+.carmenta-primary-toolbar .carmenta-insertcharacter-button em,
+.carmenta-expander-button[data-button=insertcharacter] em { background-image: url(/assets/carmenta/toolbar/primary/insertcharacter.png) }
+.carmenta-primary-toolbar .carmenta-objectspanel-button em,
+.carmenta-expander-button[data-button=objectspanel] em { background-image: url(/assets/carmenta/toolbar/primary/objectspanel.png) }
+.carmenta-primary-toolbar .carmenta-historypanel-button em,
+.carmenta-expander-button[data-button=historypanel] em { background-image: url(/assets/carmenta/toolbar/primary/historypanel.png) }
+.carmenta-primary-toolbar .carmenta-notespanel-button em,
+.carmenta-expander-button[data-button=notespanel] em { background-image: url(/assets/carmenta/toolbar/primary/notespanel.png) }
+.carmenta-primary-toolbar .carmenta-todospanel-button em,
+.carmenta-expander-button[data-button=todospanel] em { background-image: url(/assets/carmenta/toolbar/primary/todospanel.png) }
+.carmenta-primary-toolbar .carmenta-notespanel-button em,
+.carmenta-expander-button[data-button=notespanel] em { background-image: url(/assets/carmenta/toolbar/primary/notespanel.png) }
+.carmenta-primary-toolbar .carmenta-todospanel-button em,
+.carmenta-expander-button[data-button=todospanel] em { background-image: url(/assets/carmenta/toolbar/primary/todospanel.png) }
+
+
+/* Toolbar: Editable Region Toolbar
+ *----------------------------------------------------------------------------*/
+.carmenta-editable-toolbar {
+ padding: 3px 13px 1px 10px;
+ border-top: 1px solid #E2E1E2;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, rgb(198,198,198)), color-stop(1, rgb(210,210,209)));
+ background-image: -moz-linear-gradient(center bottom, rgb(198,198,198) 0%, rgb(210,210,209) 100%);
+ &:after {
+ content: '\00a0';
+ display: block;
+ visibility: hidden;
+ clear: both;
+ height: 0;
+ }
+ .carmenta-separator,
+ .carmenta-line-separator {
+ height: 18px;
+ padding: 0;
+ margin: 0 7px 2px;
+ }
+ .carmenta-separator {
+ margin: 0 3px 2px;
+ }
+ .carmenta-button-group {
+ white-space: nowrap;
+ .carmenta-button:first-child {
+ width: 23px;
+ }
+ }
+ .carmenta-button {