phrasing 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +142 -0
- data/MIT-LICENSE +20 -0
- data/README.md +93 -0
- data/Rakefile +35 -0
- data/app/assets/fonts/icomoon.dev.svg +38 -0
- data/app/assets/fonts/icomoon.eot +0 -0
- data/app/assets/fonts/icomoon.svg +38 -0
- data/app/assets/fonts/icomoon.ttf +0 -0
- data/app/assets/fonts/icomoon.woff +0 -0
- data/app/assets/images/phrasing_information_icon.png +0 -0
- data/app/assets/javascripts/editor.js +318 -0
- data/app/assets/javascripts/head.js +423 -0
- data/app/assets/javascripts/phrasing.js.erb +148 -0
- data/app/assets/javascripts/spin.js +355 -0
- data/app/assets/stylesheets/phrasing.css.scss +240 -0
- data/app/assets/stylesheets/phrasing_edit_mode_bubble.css.scss +117 -0
- data/app/assets/stylesheets/phrasing_engine.css +470 -0
- data/app/assets/stylesheets/phrasing_fonts.css.scss +60 -0
- data/app/controllers/phrasing_phrases_controller.rb +126 -0
- data/app/helpers/inline_helper.rb +47 -0
- data/app/models/phrasing_phrase.rb +97 -0
- data/app/views/layouts/phrasing.html.haml +12 -0
- data/app/views/phrasing/_initializer.html.haml +25 -0
- data/app/views/phrasing/_menu.html.haml +8 -0
- data/app/views/phrasing/_messages.html.haml +4 -0
- data/app/views/phrasing/_production_warning.html.haml +4 -0
- data/app/views/phrasing_phrases/edit.html.haml +7 -0
- data/app/views/phrasing_phrases/help.html.haml +17 -0
- data/app/views/phrasing_phrases/import_export.html.haml +18 -0
- data/app/views/phrasing_phrases/index.html.haml +17 -0
- data/config/routes.rb +12 -0
- data/db/migrate/20120313191745_create_phrasing_phrases.rb +11 -0
- data/lib/phrasing.rb +72 -0
- data/lib/phrasing/ambiguous_phrases_error.rb +3 -0
- data/lib/phrasing/implementation.rb +19 -0
- data/lib/phrasing/phrasable_error_handler.rb +9 -0
- data/lib/phrasing/simple.rb +3 -0
- data/lib/phrasing/version.rb +3 -0
- data/lib/tasks/phrasing_tasks.rake +57 -0
- data/phrasing.gemspec +21 -0
- metadata +135 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
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="" d="M0,384L 448 -64L0 -64 z" horiz-adv-x="0" />
|
13
|
+
<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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=" " 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="" d="M0,384L 448 -64L0 -64 z" horiz-adv-x="0" />
|
13
|
+
<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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=" " horiz-adv-x="224" />
|
38
|
+
</font></defs></svg>
|
Binary file
|
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
|
+
})();
|