phrasing 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +10 -0
  3. data/Gemfile.lock +142 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +93 -0
  6. data/Rakefile +35 -0
  7. data/app/assets/fonts/icomoon.dev.svg +38 -0
  8. data/app/assets/fonts/icomoon.eot +0 -0
  9. data/app/assets/fonts/icomoon.svg +38 -0
  10. data/app/assets/fonts/icomoon.ttf +0 -0
  11. data/app/assets/fonts/icomoon.woff +0 -0
  12. data/app/assets/images/phrasing_information_icon.png +0 -0
  13. data/app/assets/javascripts/editor.js +318 -0
  14. data/app/assets/javascripts/head.js +423 -0
  15. data/app/assets/javascripts/phrasing.js.erb +148 -0
  16. data/app/assets/javascripts/spin.js +355 -0
  17. data/app/assets/stylesheets/phrasing.css.scss +240 -0
  18. data/app/assets/stylesheets/phrasing_edit_mode_bubble.css.scss +117 -0
  19. data/app/assets/stylesheets/phrasing_engine.css +470 -0
  20. data/app/assets/stylesheets/phrasing_fonts.css.scss +60 -0
  21. data/app/controllers/phrasing_phrases_controller.rb +126 -0
  22. data/app/helpers/inline_helper.rb +47 -0
  23. data/app/models/phrasing_phrase.rb +97 -0
  24. data/app/views/layouts/phrasing.html.haml +12 -0
  25. data/app/views/phrasing/_initializer.html.haml +25 -0
  26. data/app/views/phrasing/_menu.html.haml +8 -0
  27. data/app/views/phrasing/_messages.html.haml +4 -0
  28. data/app/views/phrasing/_production_warning.html.haml +4 -0
  29. data/app/views/phrasing_phrases/edit.html.haml +7 -0
  30. data/app/views/phrasing_phrases/help.html.haml +17 -0
  31. data/app/views/phrasing_phrases/import_export.html.haml +18 -0
  32. data/app/views/phrasing_phrases/index.html.haml +17 -0
  33. data/config/routes.rb +12 -0
  34. data/db/migrate/20120313191745_create_phrasing_phrases.rb +11 -0
  35. data/lib/phrasing.rb +72 -0
  36. data/lib/phrasing/ambiguous_phrases_error.rb +3 -0
  37. data/lib/phrasing/implementation.rb +19 -0
  38. data/lib/phrasing/phrasable_error_handler.rb +9 -0
  39. data/lib/phrasing/simple.rb +3 -0
  40. data/lib/phrasing/version.rb +3 -0
  41. data/lib/tasks/phrasing_tasks.rake +57 -0
  42. data/phrasing.gemspec +21 -0
  43. metadata +135 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ .ruby-version
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
5
+
6
+ gem 'factory_girl_rails'
7
+ gem 'haml-rails'
8
+ gem 'sqlite3'
9
+ gem 'rspec-rails'
10
+ gem 'capybara', '~> 2.0.0'
data/Gemfile.lock ADDED
@@ -0,0 +1,142 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ phrasing (0.9.1)
5
+ bootstrap-editable-rails
6
+ haml-rails
7
+ rails (>= 3.1.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionmailer (4.0.0)
13
+ actionpack (= 4.0.0)
14
+ mail (~> 2.5.3)
15
+ actionpack (4.0.0)
16
+ activesupport (= 4.0.0)
17
+ builder (~> 3.1.0)
18
+ erubis (~> 2.7.0)
19
+ rack (~> 1.5.2)
20
+ rack-test (~> 0.6.2)
21
+ activemodel (4.0.0)
22
+ activesupport (= 4.0.0)
23
+ builder (~> 3.1.0)
24
+ activerecord (4.0.0)
25
+ activemodel (= 4.0.0)
26
+ activerecord-deprecated_finders (~> 1.0.2)
27
+ activesupport (= 4.0.0)
28
+ arel (~> 4.0.0)
29
+ activerecord-deprecated_finders (1.0.3)
30
+ activesupport (4.0.0)
31
+ i18n (~> 0.6, >= 0.6.4)
32
+ minitest (~> 4.2)
33
+ multi_json (~> 1.3)
34
+ thread_safe (~> 0.1)
35
+ tzinfo (~> 0.3.37)
36
+ arel (4.0.0)
37
+ atomic (1.1.13)
38
+ bootstrap-editable-rails (0.0.5)
39
+ railties (>= 3.1)
40
+ builder (3.1.4)
41
+ capybara (2.0.3)
42
+ mime-types (>= 1.16)
43
+ nokogiri (>= 1.3.3)
44
+ rack (>= 1.0.0)
45
+ rack-test (>= 0.5.4)
46
+ selenium-webdriver (~> 2.0)
47
+ xpath (~> 1.0.0)
48
+ childprocess (0.3.9)
49
+ ffi (~> 1.0, >= 1.0.11)
50
+ diff-lcs (1.2.4)
51
+ erubis (2.7.0)
52
+ factory_girl (4.2.0)
53
+ activesupport (>= 3.0.0)
54
+ factory_girl_rails (4.2.1)
55
+ factory_girl (~> 4.2.0)
56
+ railties (>= 3.0.0)
57
+ ffi (1.9.0)
58
+ haml (4.0.3)
59
+ tilt
60
+ haml-rails (0.4)
61
+ actionpack (>= 3.1, < 4.1)
62
+ activesupport (>= 3.1, < 4.1)
63
+ haml (>= 3.1, < 4.1)
64
+ railties (>= 3.1, < 4.1)
65
+ hike (1.2.3)
66
+ i18n (0.6.5)
67
+ mail (2.5.4)
68
+ mime-types (~> 1.16)
69
+ treetop (~> 1.4.8)
70
+ mime-types (1.24)
71
+ mini_portile (0.5.1)
72
+ minitest (4.7.5)
73
+ multi_json (1.7.9)
74
+ nokogiri (1.6.0)
75
+ mini_portile (~> 0.5.0)
76
+ polyglot (0.3.3)
77
+ rack (1.5.2)
78
+ rack-test (0.6.2)
79
+ rack (>= 1.0)
80
+ rails (4.0.0)
81
+ actionmailer (= 4.0.0)
82
+ actionpack (= 4.0.0)
83
+ activerecord (= 4.0.0)
84
+ activesupport (= 4.0.0)
85
+ bundler (>= 1.3.0, < 2.0)
86
+ railties (= 4.0.0)
87
+ sprockets-rails (~> 2.0.0)
88
+ railties (4.0.0)
89
+ actionpack (= 4.0.0)
90
+ activesupport (= 4.0.0)
91
+ rake (>= 0.8.7)
92
+ thor (>= 0.18.1, < 2.0)
93
+ rake (10.1.0)
94
+ rspec-core (2.14.5)
95
+ rspec-expectations (2.14.2)
96
+ diff-lcs (>= 1.1.3, < 2.0)
97
+ rspec-mocks (2.14.3)
98
+ rspec-rails (2.14.0)
99
+ actionpack (>= 3.0)
100
+ activesupport (>= 3.0)
101
+ railties (>= 3.0)
102
+ rspec-core (~> 2.14.0)
103
+ rspec-expectations (~> 2.14.0)
104
+ rspec-mocks (~> 2.14.0)
105
+ rubyzip (0.9.9)
106
+ selenium-webdriver (2.35.0)
107
+ childprocess (>= 0.2.5)
108
+ multi_json (~> 1.0)
109
+ rubyzip
110
+ websocket (~> 1.0.4)
111
+ sprockets (2.10.0)
112
+ hike (~> 1.2)
113
+ multi_json (~> 1.0)
114
+ rack (~> 1.0)
115
+ tilt (~> 1.1, != 1.3.0)
116
+ sprockets-rails (2.0.0)
117
+ actionpack (>= 3.0)
118
+ activesupport (>= 3.0)
119
+ sprockets (~> 2.8)
120
+ sqlite3 (1.3.8)
121
+ thor (0.18.1)
122
+ thread_safe (0.1.2)
123
+ atomic
124
+ tilt (1.4.1)
125
+ treetop (1.4.15)
126
+ polyglot
127
+ polyglot (>= 0.3.1)
128
+ tzinfo (0.3.37)
129
+ websocket (1.0.7)
130
+ xpath (1.0.0)
131
+ nokogiri (~> 1.3)
132
+
133
+ PLATFORMS
134
+ ruby
135
+
136
+ DEPENDENCIES
137
+ capybara (~> 2.0.0)
138
+ factory_girl_rails
139
+ haml-rails
140
+ phrasing!
141
+ rspec-rails
142
+ sqlite3
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Infinum
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # Phrasing!
2
+
3
+ ![Phrasing](http://www.miataturbo.net/attachments/miata-parts-sale-trade-5/74257-lots-leftovers-near-boston-archer-phrasing2-300x225-jpg?dateline=1366600534)
4
+
5
+ Phrasing is a gem for live editing phrases (copy) on websites.
6
+
7
+ ## Installation
8
+
9
+ Include the gem in your Gemfile
10
+
11
+ ```ruby
12
+ gem "phrasing"
13
+ ```
14
+
15
+ Run the install script:
16
+
17
+ ```ruby
18
+ rake phrasing:install
19
+ ```
20
+
21
+ This will create a migration file and a config file where you can edit the name of the route to see all the phrases.
22
+
23
+ Migrate your database
24
+ ```ruby
25
+ rake db:migrate
26
+ ```
27
+
28
+ ## Setup
29
+
30
+ The rake task will also generate a PhrasingHelper.rb file in your <tt>app/helpers</tt> folder where you will need to implement your <tt>can_edit_phrases?</tt> method. Example:
31
+
32
+ ```ruby
33
+ module PhrasingHelper
34
+
35
+ def can_edit_phrases?
36
+ current_user.is_admin?
37
+ end
38
+
39
+ end
40
+ ```
41
+ Include the phrasing **html** initializer at the top of your body
42
+
43
+ ```haml
44
+ = render 'phrasing/initializer'
45
+ ```
46
+
47
+ Include the required **javascript** file (most often in your application.js file):
48
+
49
+ ```javascript
50
+ //= require phrasing
51
+ ```
52
+
53
+ Include the required **stylesheet** file (most often in your application.css file):
54
+
55
+ ```css
56
+ //= require phrasing
57
+ ```
58
+
59
+ ## How to use phrasing?
60
+
61
+ Start with adding your phrases simply by writting in your view file:
62
+
63
+ = phrase('my-first-phrase')
64
+
65
+ Apart from editing phrases (basically, Rails translations) you can also inline edit your models attributes, just use the `model_phrase` method:
66
+
67
+ = model_phrase(@post, :title)
68
+
69
+ Where <tt>@post</tt> is a object with a <tt>title</tt> attribute.
70
+
71
+ ## Security
72
+
73
+ Since Phrasing can be used to update any attribute in any table (using the model_phrase method), special care must be taken into consideration from a security standpoint.
74
+
75
+ By default, Phrasing doesn't allow updating of any attribute apart from <<t>PhrasingPhrase.value</tt>. To be able to work with other attributes, you need to whitelist them.
76
+
77
+ In the <tt>config/initializers/phrasing.rb</tt> file you can whitelist your model attributes like this:
78
+
79
+ ```ruby
80
+ Phrasing.white_list = ["Post.title", "Post.body"]
81
+ ```
82
+
83
+ or you can whitelist all of them (not recommended) with:
84
+
85
+ ```ruby
86
+ Phrasing.allow_update_on_all_models_and_attributes = true
87
+ ```
88
+
89
+ ## Authors
90
+
91
+ Copyright (c) 2013, Infinum
92
+
93
+ Phrasing relies heavily (or is built) on two other libraries: the Copycat gem and the ZenPen library. So thank you to the authors and all the contributors!
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+ begin
9
+ require 'rdoc/task'
10
+ rescue LoadError
11
+ require 'rdoc/rdoc'
12
+ require 'rake/rdoctask'
13
+ RDoc::Task = Rake::RDocTask
14
+ end
15
+
16
+ RDoc::Task.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Phrasing'
19
+ rdoc.options << '--line-numbers'
20
+ rdoc.rdoc_files.include('README.rdoc')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
25
+ load 'rails/tasks/engine.rake'
26
+
27
+ Bundler::GemHelper.install_tasks
28
+
29
+
30
+ require 'rspec/core/rake_task'
31
+
32
+ desc "Run all RSpec tests"
33
+ RSpec::Core::RakeTask.new(:spec)
34
+
35
+ task :default => :spec
@@ -0,0 +1,38 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>
5
+ This is a custom SVG font generated by IcoMoon.
6
+ <iconset grid="14"></iconset>
7
+ </metadata>
8
+ <defs>
9
+ <font id="icomoon" horiz-adv-x="448" >
10
+ <font-face units-per-em="448" ascent="384" descent="-64" />
11
+ <missing-glyph horiz-adv-x="448" />
12
+ <glyph class="hidden" unicode="&#xf000;" d="M0,384L 448 -64L0 -64 z" horiz-adv-x="0" />
13
+ <glyph unicode="&#xe000;" d="M 448,384 L 448,216 L 387.511,276.489 L 294.761,183.739 L 247.739,230.761 L 340.489,323.511 L 280,384 ZM 107.511,323.511 L 200.261,230.761 L 153.239,183.739 L 60.489,276.489 L 0,216 L 0,384 L 168,384 ZM 387.511,43.511 L 448,104 L 448-64 L 280-64 L 340.489-3.511 L 247.739,89.239 L 294.761,136.261 ZM 200.261,89.239 L 107.511-3.511 L 168-64 L 0-64 L 0,104 L 60.489,43.511 L 153.239,136.261 Z" data-tags="expand, enlarge, maximize, fullscreen" />
14
+ <glyph unicode="&#xe001;" d="M 252.322,188.35l 81.046,0 c-10.276,39.704-41.342,70.798-81.046,81.046L 252.322,188.35 zM 252.322,131.65l0-81.018 c 39.704,10.22, 70.77,41.342, 81.046,81.018L 252.322,131.65 zM 195.622,188.35L 195.622,269.396 c-39.704-10.248-70.826-41.342-81.046-81.046L 195.622,188.35 zM 195.622,131.65L 114.576,131.65 c 10.22-39.676, 41.342-70.798, 81.046-81.018L 195.622,131.65 zM 252.322,327.258c 71.036-12.026, 126.868-67.872, 138.908-138.908L 448,188.35 C 435.036,290.704, 354.704,371.064, 252.322,384L 252.322,327.258 z
15
+ M 56.714,188.35C 68.74,259.4, 124.572,315.232, 195.622,327.258L 195.622,384 C 93.296,371.064, 12.908,290.704,0,188.35L 56.714,188.35 zM 195.622-7.23c-71.036,12.026-126.868,67.816-138.908,138.88L0,131.65 C 12.908,29.296, 93.296-51.092, 195.622-64
16
+ L 195.622-7.23 zM 391.23,131.65c-12.026-71.064-67.872-126.854-138.908-138.88L 252.322-64 C 354.704-51.092, 435.036,29.296, 448,131.65
17
+ L 391.23,131.65 z" data-tags="target, goal" />
18
+ <glyph unicode="&#xe002;" d="M 65.618,1.618c-87.486,87.472-87.486,229.306,0,316.778
19
+ c 87.472,87.486, 229.306,87.486, 316.778,0c 87.486-87.472, 87.486-229.306,0-316.778C 294.91-85.868, 153.090-85.868, 65.618,1.618z M 342.79,278.79
20
+ L 105.21,41.21c 65.618-65.618, 171.976-65.618, 237.594,0S 408.408,213.186, 342.79,278.79z" data-tags="contrast" />
21
+ <glyph unicode="&#xe003;" d="M 420-64L 28-64 c-15.456,0-28,12.544-28,28L0,356 c0,15.456, 12.544,28, 28,28l 336,0 l 84-84l0-336
22
+ C 448-51.456, 435.456-64, 420-64z M 112,6c0-7.742, 6.272-14, 14-14l 196,0 c 7.742,0, 14,6.258, 14,14l0,112 c0,7.742-6.258,14-14,14L 126,132 c-7.728,0-14-6.258-14-14L 112,6 z
23
+ M 308,314c0,7.742-6.258,14-14,14s-14-6.258-14-14l0-42 c0-7.742, 6.258-14, 14-14s 14,6.258, 14,14L 308,314 z M 392,286l-42,42l-14,0 l0-98 c0-7.742-6.258-14-14-14L 126,216
24
+ c-7.728,0-14,6.258-14,14L 112,328 L 70,328 C 62.272,328, 56,321.742, 56,314l0-308 c0-7.742, 6.272-14, 14-14l 14,0 L 84,146 c0,7.742, 6.272,14, 14,14l 252,0 c 7.742,0, 14-6.258, 14-14l0-154 l 14,0
25
+ c 7.742,0, 14,6.258, 14,14L 392,286 z" data-tags="floppy, disk, save, store" />
26
+ <glyph unicode="&#xe004;" d="M 28,132 L 196,132 L 196-36 L 135.511,24.489 L 47.136-63.886 L 0.114-16.864 L 88.489,71.511 ZM 359.511,71.511 L 447.886-16.864 L 400.864-63.886 L 312.489,24.489 L 252-36 L 252,132 L 420,132 ZM 420,188 L 252,188 L 252,356 L 312.489,295.511 L 400.864,383.886 L 447.886,336.864 L 359.511,248.489 ZM 135.511,295.511 L 196,356 L 196,188 L 28,188 L 88.489,248.489 L 0.114,336.864 L 47.136,383.886 Z" data-tags="contract, minimize, shrink, collapse" />
27
+ <glyph unicode="&#xe005;" d="M 417.111,351.344l-1.762,1.768c-41.19,41.184-108.585,41.184-149.768,0L 170.159,257.678
28
+ c-41.184-41.183-41.184-108.577,0-149.761l 1.761-1.761c 3.426-3.433, 7.064-6.529, 10.822-9.388l 34.934,34.934
29
+ c-4.070,2.404-7.93,5.281-11.426,8.776l-1.768,1.768c-22.362,22.355-22.362,58.744,0,81.108L 299.913,318.779
30
+ c 22.363,22.364, 58.745,22.364, 81.106,0l 1.768-1.76c 22.356-22.363, 22.356-58.753,0-81.108l-43.175-43.175
31
+ c 7.495-18.51, 11.046-38.238, 10.735-57.919l 66.764,66.764C 458.296,242.765, 458.296,310.159, 417.111,351.344zM 276.081,213.841c-3.426,3.426-7.064,6.528-10.822,9.38l-34.934-34.926c 4.071-2.405, 7.93-5.282, 11.426-8.777l 1.768-1.768
32
+ c 22.363-22.363, 22.363-58.744,0-81.107L 148.088,1.209c-22.364-22.357-58.746-22.357-81.107,0l-1.768,1.768
33
+ c-22.355,22.365-22.355,58.746,0,81.107l 43.176,43.175c-7.496,18.509-11.045,38.238-10.735,57.919l-66.763-66.762
34
+ c-41.184-41.183-41.184-108.578,0-149.767l 1.761-1.764c 41.191-41.181, 108.584-41.181, 149.768,0l 95.423,95.427
35
+ c 41.184,41.183, 41.184,108.585,0,149.768L 276.081,213.841z" data-tags="link, chain, url, uri, anchor" />
36
+ <glyph unicode="&#xe006;" d="M 334.75,182.25q 4.25-10.25 -3.5-17.5l-112-112q-4.5-4.75 -11.25-4.75t-11.25,4.75l-112,112q-7.75,7.25 -3.5,17.5q 4.25,9.75 14.75,9.75l 64,0 l0,112 q0,6.5 4.75,11.25t 11.25,4.75l 64,0 q 6.5,0 11.25-4.75t 4.75-11.25l0-112 l 64,0 q 10.5,0 14.75-9.75zM 408,128q 3.5,0 5.75-2.25t 2.25-5.75l0-144 q0-3.5 -2.25-5.75t-5.75-2.25l-400,0 q-3.5,0 -5.75,2.25t-2.25,5.75l0,144 q0,3.5 2.25,5.75 t 5.75,2.25l 48,0 q 3.5,0 5.75-2.25t 2.25-5.75l0-88 l 288,0 l0,88 q0,3.5 2.25,5.75t 5.75,2.25l 48,0 z" horiz-adv-x="416" data-tags="download-alt, arrow, store, save" />
37
+ <glyph unicode="&#x20;" horiz-adv-x="224" />
38
+ </font></defs></svg>
Binary file
@@ -0,0 +1,38 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>
5
+ This is a custom SVG font generated by IcoMoon.
6
+ <iconset grid="14"></iconset>
7
+ </metadata>
8
+ <defs>
9
+ <font id="icomoon" horiz-adv-x="448" >
10
+ <font-face units-per-em="448" ascent="384" descent="-64" />
11
+ <missing-glyph horiz-adv-x="448" />
12
+ <glyph class="hidden" unicode="&#xf000;" d="M0,384L 448 -64L0 -64 z" horiz-adv-x="0" />
13
+ <glyph unicode="&#xe000;" d="M 448,384 L 448,216 L 387.511,276.489 L 294.761,183.739 L 247.739,230.761 L 340.489,323.511 L 280,384 ZM 107.511,323.511 L 200.261,230.761 L 153.239,183.739 L 60.489,276.489 L 0,216 L 0,384 L 168,384 ZM 387.511,43.511 L 448,104 L 448-64 L 280-64 L 340.489-3.511 L 247.739,89.239 L 294.761,136.261 ZM 200.261,89.239 L 107.511-3.511 L 168-64 L 0-64 L 0,104 L 60.489,43.511 L 153.239,136.261 Z" />
14
+ <glyph unicode="&#xe001;" d="M 252.322,188.35l 81.046,0 c-10.276,39.704-41.342,70.798-81.046,81.046L 252.322,188.35 zM 252.322,131.65l0-81.018 c 39.704,10.22, 70.77,41.342, 81.046,81.018L 252.322,131.65 zM 195.622,188.35L 195.622,269.396 c-39.704-10.248-70.826-41.342-81.046-81.046L 195.622,188.35 zM 195.622,131.65L 114.576,131.65 c 10.22-39.676, 41.342-70.798, 81.046-81.018L 195.622,131.65 zM 252.322,327.258c 71.036-12.026, 126.868-67.872, 138.908-138.908L 448,188.35 C 435.036,290.704, 354.704,371.064, 252.322,384L 252.322,327.258 z
15
+ M 56.714,188.35C 68.74,259.4, 124.572,315.232, 195.622,327.258L 195.622,384 C 93.296,371.064, 12.908,290.704,0,188.35L 56.714,188.35 zM 195.622-7.23c-71.036,12.026-126.868,67.816-138.908,138.88L0,131.65 C 12.908,29.296, 93.296-51.092, 195.622-64
16
+ L 195.622-7.23 zM 391.23,131.65c-12.026-71.064-67.872-126.854-138.908-138.88L 252.322-64 C 354.704-51.092, 435.036,29.296, 448,131.65
17
+ L 391.23,131.65 z" />
18
+ <glyph unicode="&#xe002;" d="M 65.618,1.618c-87.486,87.472-87.486,229.306,0,316.778
19
+ c 87.472,87.486, 229.306,87.486, 316.778,0c 87.486-87.472, 87.486-229.306,0-316.778C 294.91-85.868, 153.090-85.868, 65.618,1.618z M 342.79,278.79
20
+ L 105.21,41.21c 65.618-65.618, 171.976-65.618, 237.594,0S 408.408,213.186, 342.79,278.79z" />
21
+ <glyph unicode="&#xe003;" d="M 420-64L 28-64 c-15.456,0-28,12.544-28,28L0,356 c0,15.456, 12.544,28, 28,28l 336,0 l 84-84l0-336
22
+ C 448-51.456, 435.456-64, 420-64z M 112,6c0-7.742, 6.272-14, 14-14l 196,0 c 7.742,0, 14,6.258, 14,14l0,112 c0,7.742-6.258,14-14,14L 126,132 c-7.728,0-14-6.258-14-14L 112,6 z
23
+ M 308,314c0,7.742-6.258,14-14,14s-14-6.258-14-14l0-42 c0-7.742, 6.258-14, 14-14s 14,6.258, 14,14L 308,314 z M 392,286l-42,42l-14,0 l0-98 c0-7.742-6.258-14-14-14L 126,216
24
+ c-7.728,0-14,6.258-14,14L 112,328 L 70,328 C 62.272,328, 56,321.742, 56,314l0-308 c0-7.742, 6.272-14, 14-14l 14,0 L 84,146 c0,7.742, 6.272,14, 14,14l 252,0 c 7.742,0, 14-6.258, 14-14l0-154 l 14,0
25
+ c 7.742,0, 14,6.258, 14,14L 392,286 z" />
26
+ <glyph unicode="&#xe004;" d="M 28,132 L 196,132 L 196-36 L 135.511,24.489 L 47.136-63.886 L 0.114-16.864 L 88.489,71.511 ZM 359.511,71.511 L 447.886-16.864 L 400.864-63.886 L 312.489,24.489 L 252-36 L 252,132 L 420,132 ZM 420,188 L 252,188 L 252,356 L 312.489,295.511 L 400.864,383.886 L 447.886,336.864 L 359.511,248.489 ZM 135.511,295.511 L 196,356 L 196,188 L 28,188 L 88.489,248.489 L 0.114,336.864 L 47.136,383.886 Z" />
27
+ <glyph unicode="&#xe005;" d="M 417.111,351.344l-1.762,1.768c-41.19,41.184-108.585,41.184-149.768,0L 170.159,257.678
28
+ c-41.184-41.183-41.184-108.577,0-149.761l 1.761-1.761c 3.426-3.433, 7.064-6.529, 10.822-9.388l 34.934,34.934
29
+ c-4.070,2.404-7.93,5.281-11.426,8.776l-1.768,1.768c-22.362,22.355-22.362,58.744,0,81.108L 299.913,318.779
30
+ c 22.363,22.364, 58.745,22.364, 81.106,0l 1.768-1.76c 22.356-22.363, 22.356-58.753,0-81.108l-43.175-43.175
31
+ c 7.495-18.51, 11.046-38.238, 10.735-57.919l 66.764,66.764C 458.296,242.765, 458.296,310.159, 417.111,351.344zM 276.081,213.841c-3.426,3.426-7.064,6.528-10.822,9.38l-34.934-34.926c 4.071-2.405, 7.93-5.282, 11.426-8.777l 1.768-1.768
32
+ c 22.363-22.363, 22.363-58.744,0-81.107L 148.088,1.209c-22.364-22.357-58.746-22.357-81.107,0l-1.768,1.768
33
+ c-22.355,22.365-22.355,58.746,0,81.107l 43.176,43.175c-7.496,18.509-11.045,38.238-10.735,57.919l-66.763-66.762
34
+ c-41.184-41.183-41.184-108.578,0-149.767l 1.761-1.764c 41.191-41.181, 108.584-41.181, 149.768,0l 95.423,95.427
35
+ c 41.184,41.183, 41.184,108.585,0,149.768L 276.081,213.841z" />
36
+ <glyph unicode="&#xe006;" d="M 334.75,182.25q 4.25-10.25 -3.5-17.5l-112-112q-4.5-4.75 -11.25-4.75t-11.25,4.75l-112,112q-7.75,7.25 -3.5,17.5q 4.25,9.75 14.75,9.75l 64,0 l0,112 q0,6.5 4.75,11.25t 11.25,4.75l 64,0 q 6.5,0 11.25-4.75t 4.75-11.25l0-112 l 64,0 q 10.5,0 14.75-9.75zM 408,128q 3.5,0 5.75-2.25t 2.25-5.75l0-144 q0-3.5 -2.25-5.75t-5.75-2.25l-400,0 q-3.5,0 -5.75,2.25t-2.25,5.75l0,144 q0,3.5 2.25,5.75 t 5.75,2.25l 48,0 q 3.5,0 5.75-2.25t 2.25-5.75l0-88 l 288,0 l0,88 q0,3.5 2.25,5.75t 5.75,2.25l 48,0 z" horiz-adv-x="416" />
37
+ <glyph unicode="&#x20;" horiz-adv-x="224" />
38
+ </font></defs></svg>
Binary file
Binary file
@@ -0,0 +1,318 @@
1
+ var editor = (function() {
2
+
3
+ // Editor elements
4
+ var headerField, contentField, cleanSlate, lastType, currentNodeList, savedSelection;
5
+
6
+ // Editor Bubble elements
7
+ var textOptions, optionsBox, boldButton, italicButton, quoteButton, urlButton, urlInput;
8
+
9
+
10
+ function init() {
11
+ if ($('#zenpenbubble').length){
12
+ lastRange = 0;
13
+ bindElements();
14
+
15
+ // Set cursor position
16
+ var range = document.createRange();
17
+ var selection = window.getSelection();
18
+ // range.setStart(headerField, 1);
19
+ selection.removeAllRanges();
20
+ selection.addRange(range);
21
+
22
+ createEventBindings();
23
+ }
24
+ }
25
+
26
+ function createEventBindings( on ) {
27
+
28
+ // Key up bindings
29
+ document.onkeyup = checkTextHighlighting;
30
+
31
+ // Mouse bindings
32
+ document.onmousedown = checkTextHighlighting;
33
+ document.onmouseup = function( event ) {
34
+
35
+ setTimeout( function() {
36
+ checkTextHighlighting( event );
37
+ }, 1);
38
+ };
39
+
40
+ // Window bindings
41
+ window.addEventListener( 'resize', function( event ) {
42
+ updateBubblePosition();
43
+ });
44
+
45
+ // Scroll bindings. We limit the events, to free the ui
46
+ // thread and prevent stuttering. See:
47
+ // http://ejohn.org/blog/learning-from-twitter
48
+ var scrollEnabled = true;
49
+ document.body.addEventListener( 'scroll', function() {
50
+
51
+ if ( !scrollEnabled ) {
52
+ return;
53
+ }
54
+
55
+ scrollEnabled = true;
56
+
57
+ updateBubblePosition();
58
+
59
+ return setTimeout((function() {
60
+ scrollEnabled = true;
61
+ }), 250);
62
+ });
63
+ }
64
+
65
+ function bindElements() {
66
+
67
+ contentField = document.querySelector( '.content' );
68
+ textOptions = document.querySelector( '.text-options' );
69
+
70
+ optionsBox = textOptions.querySelector( '.options' );
71
+
72
+ boldButton = textOptions.querySelector( '.bold' );
73
+ boldButton.onclick = onBoldClick;
74
+
75
+ italicButton = textOptions.querySelector( '.italic' );
76
+ italicButton.onclick = onItalicClick;
77
+
78
+ // quoteButton = textOptions.querySelector( '.quote' );
79
+ // quoteButton.onclick = onQuoteClick;
80
+
81
+ urlButton = textOptions.querySelector( '.url' );
82
+ urlButton.onmousedown = onUrlClick;
83
+
84
+ urlInput = textOptions.querySelector( '.url-input' );
85
+ urlInput.onblur = onUrlInputBlur;
86
+ urlInput.onkeydown = onUrlInputKeyDown;
87
+ }
88
+
89
+ function checkTextHighlighting( event ) {
90
+
91
+ var selection = window.getSelection();
92
+
93
+ if (event.target.className === "url-input" || event.target.classList.contains( "url")) {
94
+ currentNodeList = findNodes( selection.focusNode );
95
+ updateBubbleStates();
96
+ return;
97
+ }
98
+
99
+ if (event.target.parentNode.classList != null){
100
+ if (event.target.parentNode.classList.contains("ui-inputs")){
101
+ currentNodeList = findNodes( selection.focusNode );
102
+ updateBubbleStates();
103
+ return;
104
+ }
105
+ }
106
+
107
+ // Check selections exist
108
+ if ( selection.isCollapsed === true && lastType === false ) {
109
+ onSelectorBlur();
110
+ }
111
+
112
+ // Text is selected
113
+ if ( selection.isCollapsed === false ) {
114
+
115
+ currentNodeList = findNodes( selection.focusNode );
116
+ // Find if highlighting is in the editable area
117
+ if (isContentEditable(selection.focusNode) == true) {
118
+ updateBubbleStates();
119
+ updateBubblePosition();
120
+
121
+ // Show the ui bubble
122
+ textOptions.className = "text-options active";
123
+ }
124
+ }
125
+
126
+ lastType = selection.isCollapsed;
127
+ }
128
+
129
+ function updateBubblePosition() {
130
+ var selection = window.getSelection();
131
+ var range = selection.getRangeAt(0);
132
+ var boundary = range.getBoundingClientRect();
133
+
134
+ textOptions.style.top = boundary.top - 5 + window.pageYOffset + "px";
135
+ textOptions.style.left = (boundary.left + boundary.right)/2 + "px";
136
+ }
137
+
138
+ function updateBubbleStates() {
139
+
140
+ // It would be possible to use classList here, but I feel that the
141
+ // browser support isn't quite there, and this functionality doesn't
142
+ // warrent a shim.
143
+
144
+ if ( hasNode( currentNodeList, 'B') ) {
145
+ boldButton.className = "bold active"
146
+ } else {
147
+ boldButton.className = "bold"
148
+ }
149
+
150
+ if ( hasNode( currentNodeList, 'I') ) {
151
+ italicButton.className = "italic active"
152
+ } else {
153
+ italicButton.className = "italic"
154
+ }
155
+
156
+ // if ( hasNode( currentNodeList, 'BLOCKQUOTE') ) {
157
+ // quoteButton.className = "quote active"
158
+ // } else {
159
+ // quoteButton.className = "quote"
160
+ // }
161
+
162
+ if ( hasNode( currentNodeList, 'A') ) {
163
+ urlButton.className = "url useicons active"
164
+ } else {
165
+ urlButton.className = "url useicons"
166
+ }
167
+ }
168
+
169
+ function onSelectorBlur() {
170
+
171
+ textOptions.className = "text-options fade";
172
+ setTimeout( function() {
173
+
174
+ if (textOptions.className == "text-options fade") {
175
+
176
+ textOptions.className = "text-options";
177
+ textOptions.style.top = '-999px';
178
+ textOptions.style.left = '-999px';
179
+ }
180
+ }, 260 )
181
+ }
182
+
183
+ function findNodes( element ) {
184
+
185
+ var nodeNames = {};
186
+
187
+ while ( element.parentNode ) {
188
+
189
+ nodeNames[element.nodeName] = true;
190
+ element = element.parentNode;
191
+
192
+ if ( element.nodeName === 'A' ) {
193
+ nodeNames.url = element.href;
194
+ }
195
+ }
196
+
197
+ return nodeNames;
198
+ }
199
+
200
+ function isContentEditable(element){
201
+ //if any of its parents has the class of 'phrasable' go hooray
202
+ while ( element.parentNode ) {
203
+ if (element.className !== undefined){
204
+ if (element.className.indexOf("phrasable_on")>=0){
205
+ return true;
206
+ }
207
+ }
208
+ element = element.parentNode;
209
+ }
210
+ return false;
211
+ }
212
+
213
+ function hasNode( nodeList, name ) {
214
+ return !!nodeList[ name ];
215
+ }
216
+
217
+
218
+ function onBoldClick() {
219
+ document.execCommand( 'bold', false );
220
+ }
221
+
222
+ function onItalicClick() {
223
+ document.execCommand( 'italic', false );
224
+ }
225
+
226
+ // function onQuoteClick() {
227
+
228
+ // var nodeNames = findNodes( window.getSelection().focusNode );
229
+
230
+ // if ( hasNode( nodeNames, 'BLOCKQUOTE' ) ) {
231
+ // document.execCommand( 'formatBlock', false, 'p' );
232
+ // document.execCommand( 'outdent' );
233
+ // } else {
234
+ // document.execCommand( 'formatBlock', false, 'blockquote' );
235
+ // }
236
+ // }
237
+
238
+ function onUrlClick() {
239
+
240
+ if ( optionsBox.className == 'options' ) {
241
+
242
+ optionsBox.className = 'options url-mode';
243
+
244
+ // Set timeout here to debounce the focus action
245
+ setTimeout( function() {
246
+
247
+ var nodeNames = findNodes( window.getSelection().focusNode );
248
+
249
+ if ( hasNode( nodeNames , "A" ) ) {
250
+ urlInput.value = nodeNames.url;
251
+ } else {
252
+ // Symbolize text turning into a link, which is temporary, and will never be seen.
253
+ document.execCommand( 'createLink', false, '/' );
254
+ }
255
+
256
+ // Since typing in the input box kills the highlighted text we need
257
+ // to save this selection, to add the url link if it is provided.
258
+ lastSelection = window.getSelection().getRangeAt(0);
259
+ lastType = false;
260
+
261
+ urlInput.focus();
262
+
263
+ }, 100);
264
+
265
+ } else {
266
+
267
+ optionsBox.className = 'options';
268
+ }
269
+ }
270
+
271
+ function onUrlInputKeyDown( event ) {
272
+
273
+ if ( event.keyCode === 13 ) {
274
+ event.preventDefault();
275
+ applyURL( urlInput.value );
276
+ urlInput.blur();
277
+ }
278
+ }
279
+
280
+ function onUrlInputBlur( event ) {
281
+
282
+ optionsBox.className = 'options';
283
+ applyURL( urlInput.value );
284
+ urlInput.value = '';
285
+
286
+ currentNodeList = findNodes( window.getSelection().focusNode );
287
+ updateBubbleStates();
288
+ }
289
+
290
+ function applyURL( url ) {
291
+
292
+ rehighlightLastSelection();
293
+
294
+ // Unlink any current links
295
+ document.execCommand( 'unlink', false );
296
+
297
+ if (url !== "") {
298
+
299
+ // Insert HTTP if it doesn't exist.
300
+ if ( !url.match("^(http|https)://") ) {
301
+
302
+ url = "http://" + url;
303
+ }
304
+
305
+ document.execCommand( 'createLink', false, url );
306
+ }
307
+ }
308
+
309
+ function rehighlightLastSelection() {
310
+
311
+ window.getSelection().addRange( lastSelection );
312
+ }
313
+
314
+ return {
315
+ init: init
316
+ }
317
+
318
+ })();