phrasing 2.1.0

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