ecrire 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENCE +9 -0
- data/README.md +62 -0
- data/Rakefile +72 -0
- data/bin/ecrire +42 -0
- data/ecrire.gemspec +26 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/content.coffee +319 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/ext.coffee +94 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/clipboard.coffee +98 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/image.coffee +19 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/delete.js.coffee +11 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/draft.js.coffee +42 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/help.js.coffee +6 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/save.js.coffee +61 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/sticky.js.coffee +11 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/toggle.js.coffee +10 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/code.coffee +39 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/heading.coffee +19 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/image.coffee +129 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/link.coffee +44 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/lists.coffee +48 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/word.coffee +56 -0
- data/lib/ecrire/app/assets/javascripts/admin/posts/header.coffee +69 -0
- data/lib/ecrire/app/assets/javascripts/admin/posts/new.js.coffee +7 -0
- data/lib/ecrire/app/assets/javascripts/admin/posts/title.coffee +15 -0
- data/lib/ecrire/app/assets/javascripts/admin.js +5 -0
- data/lib/ecrire/app/assets/javascripts/application.js +21 -0
- data/lib/ecrire/app/assets/javascripts/shared/overlay.js.coffee +29 -0
- data/lib/ecrire/app/assets/javascripts/shared/popup.js.coffee +7 -0
- data/lib/ecrire/app/assets/javascripts/vendor/moment.js +3043 -0
- data/lib/ecrire/app/assets/javascripts/vendor/prism/prism.ruby.js +25 -0
- data/lib/ecrire/app/assets/javascripts/vendor/prism.js +578 -0
- data/lib/ecrire/app/assets/stylesheets/admin/base.css.scss +98 -0
- data/lib/ecrire/app/assets/stylesheets/admin/documentation.css.scss +28 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/base.css.scss +41 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/content.css.scss +57 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/header.css.scss +62 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/image.css.scss +58 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/publish.css.scss +40 -0
- data/lib/ecrire/app/assets/stylesheets/admin/editor/save.css.scss +44 -0
- data/lib/ecrire/app/assets/stylesheets/admin/images.css.scss +64 -0
- data/lib/ecrire/app/assets/stylesheets/admin/loading.css.scss +48 -0
- data/lib/ecrire/app/assets/stylesheets/admin/mixins/animations.css.scss +30 -0
- data/lib/ecrire/app/assets/stylesheets/admin/mixins/form.css.scss +22 -0
- data/lib/ecrire/app/assets/stylesheets/admin/navigation.css.scss +96 -0
- data/lib/ecrire/app/assets/stylesheets/admin/posts.css.scss +46 -0
- data/lib/ecrire/app/assets/stylesheets/admin/variables.css.scss +7 -0
- data/lib/ecrire/app/assets/stylesheets/admin.css.scss +5 -0
- data/lib/ecrire/app/assets/stylesheets/application.css.scss +12 -0
- data/lib/ecrire/app/assets/stylesheets/sessions.css.scss +97 -0
- data/lib/ecrire/app/assets/stylesheets/shared/main.css.scss +5 -0
- data/lib/ecrire/app/assets/stylesheets/shared/popup.css.scss +76 -0
- data/lib/ecrire/app/assets/stylesheets/vendor/prism/ruby.scss +11 -0
- data/lib/ecrire/app/assets/stylesheets/vendor/prism.scss +149 -0
- data/lib/ecrire/app/controllers/admin/application_controller.rb +16 -0
- data/lib/ecrire/app/controllers/admin/configurations/images_controller.rb +28 -0
- data/lib/ecrire/app/controllers/admin/images_controller.rb +35 -0
- data/lib/ecrire/app/controllers/admin/labels_controller.rb +18 -0
- data/lib/ecrire/app/controllers/admin/partials_controller.rb +43 -0
- data/lib/ecrire/app/controllers/admin/posts_controller.rb +90 -0
- data/lib/ecrire/app/controllers/admin/properties_controller.rb +35 -0
- data/lib/ecrire/app/controllers/application_controller.rb +29 -0
- data/lib/ecrire/app/controllers/concerns/.keep +0 -0
- data/lib/ecrire/app/controllers/ecrire/posts_controller.rb +42 -0
- data/lib/ecrire/app/controllers/images_controller.rb +2 -0
- data/lib/ecrire/app/controllers/onboarding/databases_controller.rb +67 -0
- data/lib/ecrire/app/controllers/onboarding/users_controller.rb +32 -0
- data/lib/ecrire/app/controllers/onboarding_controller.rb +20 -0
- data/lib/ecrire/app/controllers/partials_controller.rb +8 -0
- data/lib/ecrire/app/controllers/sessions_controller.rb +23 -0
- data/lib/ecrire/app/controllers/static_controller.rb +5 -0
- data/lib/ecrire/app/forms/admin/image_builder.rb +24 -0
- data/lib/ecrire/app/forms/admin/partial_builder.rb +105 -0
- data/lib/ecrire/app/forms/admin/post_builder.rb +47 -0
- data/lib/ecrire/app/helpers/admin/images_helper.rb +60 -0
- data/lib/ecrire/app/helpers/admin/labels_helper.rb +26 -0
- data/lib/ecrire/app/helpers/admin/posts_helper.rb +26 -0
- data/lib/ecrire/app/helpers/application_helper.rb +64 -0
- data/lib/ecrire/app/helpers/content_tag_helper.rb +91 -0
- data/lib/ecrire/app/helpers/open_graph_helper.rb +45 -0
- data/lib/ecrire/app/helpers/posts_helper.rb +19 -0
- data/lib/ecrire/app/models/admin/image.rb +108 -0
- data/lib/ecrire/app/models/admin/partial.rb +4 -0
- data/lib/ecrire/app/models/admin/post.rb +56 -0
- data/lib/ecrire/app/models/concerns/.keep +0 -0
- data/lib/ecrire/app/models/image.rb +5 -0
- data/lib/ecrire/app/models/label.rb +3 -0
- data/lib/ecrire/app/models/partial.rb +3 -0
- data/lib/ecrire/app/models/post.rb +90 -0
- data/lib/ecrire/app/models/property/image.rb +30 -0
- data/lib/ecrire/app/models/property/label.rb +28 -0
- data/lib/ecrire/app/models/user.rb +31 -0
- data/lib/ecrire/app/strategies/password_strategy.rb +17 -0
- data/lib/ecrire/app/views/admin/configurations/images/complete.html.erb +6 -0
- data/lib/ecrire/app/views/admin/configurations/images/show.html.erb +14 -0
- data/lib/ecrire/app/views/admin/images/_errors.html.erb +14 -0
- data/lib/ecrire/app/views/admin/images/_form.html.erb +15 -0
- data/lib/ecrire/app/views/admin/images/destroy.js.erb +0 -0
- data/lib/ecrire/app/views/admin/images/errors.js.erb +1 -0
- data/lib/ecrire/app/views/admin/images/update.js.erb +1 -0
- data/lib/ecrire/app/views/admin/posts/_documentation.html.erb +61 -0
- data/lib/ecrire/app/views/admin/posts/_list.html.erb +18 -0
- data/lib/ecrire/app/views/admin/posts/_post.html.erb +3 -0
- data/lib/ecrire/app/views/admin/posts/edit.html.erb +73 -0
- data/lib/ecrire/app/views/admin/posts/help.js.erb +1 -0
- data/lib/ecrire/app/views/admin/posts/index.js.erb +1 -0
- data/lib/ecrire/app/views/admin/posts/title.html.erb +10 -0
- data/lib/ecrire/app/views/admin/posts/update/content.js.erb +1 -0
- data/lib/ecrire/app/views/admin/posts/update/title.js.erb +1 -0
- data/lib/ecrire/app/views/admin/properties/image/create.js.erb +14 -0
- data/lib/ecrire/app/views/admin/properties/image/destroy.js.erb +6 -0
- data/lib/ecrire/app/views/admin/properties/label/create.js.erb +8 -0
- data/lib/ecrire/app/views/admin/properties/label/destroy.js.erb +2 -0
- data/lib/ecrire/app/views/layouts/admin/application.html.erb +47 -0
- data/lib/ecrire/app/views/partials/show.html.erb +14 -0
- data/lib/ecrire/app/views/sessions/_form.html.erb +18 -0
- data/lib/ecrire/app/views/sessions/_navigation.html.erb +24 -0
- data/lib/ecrire/app/views/sessions/new.html.erb +1 -0
- data/lib/ecrire/application.rb +18 -0
- data/lib/ecrire/commands/base.rb +9 -0
- data/lib/ecrire/commands/console.rb +21 -0
- data/lib/ecrire/commands/new.rb +47 -0
- data/lib/ecrire/commands/server.rb +27 -0
- data/lib/ecrire/commands.rb +19 -0
- data/lib/ecrire/config/environment/development.rb +12 -0
- data/lib/ecrire/config/environment/production.rb +12 -0
- data/lib/ecrire/config/environment/test.rb +3 -0
- data/lib/ecrire/config/environment.rb +46 -0
- data/lib/ecrire/config/onboarding_routes.rb +11 -0
- data/lib/ecrire/config/routes.rb +32 -0
- data/lib/ecrire/db/migrate/20131111222709_create_posts.rb +16 -0
- data/lib/ecrire/db/migrate/20131113200949_create_users.rb +12 -0
- data/lib/ecrire/db/migrate/20131114205041_add_excerpt_to_post.rb +5 -0
- data/lib/ecrire/db/migrate/20131221181640_add_javascript_to_posts.rb +5 -0
- data/lib/ecrire/db/migrate/20131221195338_create_partials.rb +12 -0
- data/lib/ecrire/db/migrate/20140115215122_create_images.rb +12 -0
- data/lib/ecrire/db/migrate/20140209144412_add_favorite_flag_to_image.rb +5 -0
- data/lib/ecrire/db/migrate/20140617224837_create_labels.rb +12 -0
- data/lib/ecrire/db/migrate/20140618321984_add_properties_to_posts.rb +6 -0
- data/lib/ecrire/db/migrate/20150113839713_convert_markdown_in_post_content.rb +6 -0
- data/lib/ecrire/db/migrate/20150120093481_add_preview_to_posts.rb +8 -0
- data/lib/ecrire/db/schema.rb +76 -0
- data/lib/ecrire/locales/admin/configurations/images/en.yml +3 -0
- data/lib/ecrire/locales/admin/en.yml +26 -0
- data/lib/ecrire/locales/admin/images/en.yml +5 -0
- data/lib/ecrire/locales/admin/partials/en.yml +18 -0
- data/lib/ecrire/locales/admin/posts/en.yml +14 -0
- data/lib/ecrire/locales/en.yml +9 -0
- data/lib/ecrire/onboarding/assets/images/.keep +0 -0
- data/lib/ecrire/onboarding/assets/images/background.png +0 -0
- data/lib/ecrire/onboarding/assets/images/github-logo.png +0 -0
- data/lib/ecrire/onboarding/assets/images/profile.png +0 -0
- data/lib/ecrire/onboarding/assets/images/twitter-logo.png +0 -0
- data/lib/ecrire/onboarding/assets/javascripts/base.js +2 -0
- data/lib/ecrire/onboarding/assets/javascripts/databases/information.js.coffee +17 -0
- data/lib/ecrire/onboarding/assets/javascripts/message.js.coffee +5 -0
- data/lib/ecrire/onboarding/assets/stylesheets/base.css.scss +80 -0
- data/lib/ecrire/onboarding/assets/stylesheets/complete.css.scss +3 -0
- data/lib/ecrire/onboarding/assets/stylesheets/fonts.css.scss +17 -0
- data/lib/ecrire/onboarding/assets/stylesheets/form.css.scss +25 -0
- data/lib/ecrire/onboarding/assets/stylesheets/message.css.scss +11 -0
- data/lib/ecrire/onboarding/assets/stylesheets/terminal.css.scss +16 -0
- data/lib/ecrire/onboarding/assets/stylesheets/variables.css.scss +3 -0
- data/lib/ecrire/onboarding/assets/stylesheets/welcome.css.scss +62 -0
- data/lib/ecrire/onboarding/views/layouts/application.html.erb +16 -0
- data/lib/ecrire/onboarding/views/onboarding/complete.html.erb +6 -0
- data/lib/ecrire/onboarding/views/onboarding/databases/index.html.erb +34 -0
- data/lib/ecrire/onboarding/views/onboarding/users/index.html.erb +16 -0
- data/lib/ecrire/onboarding/views/onboarding/welcome.html.erb +12 -0
- data/lib/ecrire/railtie/onboarding.rb +63 -0
- data/lib/ecrire/railtie/theme.rb +69 -0
- data/lib/ecrire/railtie.rb +30 -0
- data/lib/ecrire/tasks/assets.rake +15 -0
- data/lib/ecrire/tasks/routes.rake +6 -0
- data/lib/ecrire/template/Gemfile +31 -0
- data/lib/ecrire/template/Rakefile +4 -0
- data/lib/ecrire/template/assets/images/.keep +0 -0
- data/lib/ecrire/template/assets/javascripts/base.js.coffee +0 -0
- data/lib/ecrire/template/assets/javascripts/post.js.coffee +0 -0
- data/lib/ecrire/template/assets/stylesheets/base.css.scss +86 -0
- data/lib/ecrire/template/assets/stylesheets/code.css.scss +24 -0
- data/lib/ecrire/template/assets/stylesheets/footer.css.scss +5 -0
- data/lib/ecrire/template/assets/stylesheets/header.css.scss +18 -0
- data/lib/ecrire/template/assets/stylesheets/home.css.scss +35 -0
- data/lib/ecrire/template/config.ru +4 -0
- data/lib/ecrire/template/controllers/posts_controller.rb +2 -0
- data/lib/ecrire/template/helpers/blog_helper.rb +2 -0
- data/lib/ecrire/template/views/layouts/application.html.erb +35 -0
- data/lib/ecrire/template/views/posts/_post.html.erb +9 -0
- data/lib/ecrire/template/views/posts/index.html.erb +13 -0
- data/lib/ecrire/template/views/posts/show.html.erb +7 -0
- data/lib/ecrire/template/views/static/about.html +0 -0
- data/lib/ecrire/template/views/static/customize/_helper.html +7 -0
- data/lib/ecrire/template/views/static/customize/_helper_used.html +6 -0
- data/lib/ecrire/template/views/static/customize/_image.html +1 -0
- data/lib/ecrire/template/views/static/customize/_index.html +1 -0
- data/lib/ecrire/template/views/static/customize/_javascript.html +1 -0
- data/lib/ecrire/template/views/static/customize/_layout.html.erb +15 -0
- data/lib/ecrire/template/views/static/customize/_post.html +3 -0
- data/lib/ecrire/template/views/static/customize.html +95 -0
- data/lib/ecrire/version.rb +3 -0
- data/lib/ecrire.rb +24 -0
- data/test/editor/controllers/admin/images_controller_test.rb +6 -0
- data/test/editor/controllers/admin/posts_controller_test.rb +90 -0
- data/test/editor/controllers/base_controller_test.rb +26 -0
- data/test/editor/controllers/images_controller_test.rb +2 -0
- data/test/editor/controllers/partials_controller_test.rb +2 -0
- data/test/editor/controllers/posts_controller_test.rb +21 -0
- data/test/editor/controllers/sessions_controller_test.rb +21 -0
- data/test/editor/helpers/base_helper_test.rb +19 -0
- data/test/editor/helpers/posts_helper_test.rb +3 -0
- data/test/editor/models/image_test.rb +33 -0
- data/test/editor/models/partial_test.rb +4 -0
- data/test/editor/models/post_test.rb +109 -0
- data/test/editor/models/user_test.rb +4 -0
- data/test/editor/test_helper.rb +28 -0
- data/test/fixtures/images.yml +11 -0
- data/test/fixtures/partials.yml +9 -0
- data/test/fixtures/posts.yml +16 -0
- data/test/fixtures/users.yml +9 -0
- data/test/initializations/railtie_test.rb +49 -0
- data/test/isolation.rb +16 -0
- data/test/themes/template/Gemfile +28 -0
- data/test/themes/template/assets/javascripts/blog.js.coffee +0 -0
- data/test/themes/template/assets/javascripts/post.js.coffee +0 -0
- data/test/themes/template/assets/stylesheets/blog.css.scss +0 -0
- data/test/themes/template/assets/stylesheets/post.css.scss +0 -0
- data/test/themes/template/config.ru +0 -0
- data/test/themes/template/views/layouts/application.html.erb +1 -0
- data/test/themes/template/views/posts/index.html.erb +0 -0
- metadata +275 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative '../onboarding_controller'
|
2
|
+
|
3
|
+
module Onboarding
|
4
|
+
class DatabasesController < OnboardingController
|
5
|
+
|
6
|
+
helper_method :user, :password, :database
|
7
|
+
|
8
|
+
def index; end;
|
9
|
+
|
10
|
+
def create
|
11
|
+
info ||= {
|
12
|
+
'adapter' => 'postgresql',
|
13
|
+
'database' => database,
|
14
|
+
'user' => user,
|
15
|
+
'password' => password,
|
16
|
+
'encoding' => 'utf8'
|
17
|
+
}
|
18
|
+
begin
|
19
|
+
ActiveRecord::Base.configurations = {
|
20
|
+
'development' => info,
|
21
|
+
'production' => info
|
22
|
+
}
|
23
|
+
ActiveRecord::Base.establish_connection
|
24
|
+
ActiveRecord::Base.connection
|
25
|
+
migrate!
|
26
|
+
rescue Exception => e
|
27
|
+
@exception = e
|
28
|
+
ActiveRecord::Base.clear_all_connections!
|
29
|
+
render 'index' and return
|
30
|
+
end
|
31
|
+
|
32
|
+
redirect_to :onboarding_users
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def migrate!
|
40
|
+
ActiveRecord::Tasks::DatabaseTasks.database_configuration = ActiveRecord::Base.configurations
|
41
|
+
ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
|
42
|
+
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
43
|
+
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
|
44
|
+
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def db_params
|
49
|
+
params.fetch(:database, {})
|
50
|
+
end
|
51
|
+
|
52
|
+
def user
|
53
|
+
@user ||= "ecrire#{SecureRandom.hex(2)}"
|
54
|
+
db_params.fetch(:user, @user)
|
55
|
+
end
|
56
|
+
|
57
|
+
def password
|
58
|
+
@password ||= SecureRandom.hex(16)
|
59
|
+
db_params.fetch(:password, @password)
|
60
|
+
end
|
61
|
+
|
62
|
+
def database
|
63
|
+
@database ||= "ecrire"
|
64
|
+
db_params.fetch(:name, @database)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Onboarding
|
2
|
+
class UsersController < OnboardingController
|
3
|
+
|
4
|
+
helper_method :user
|
5
|
+
|
6
|
+
def index;end;
|
7
|
+
|
8
|
+
def create
|
9
|
+
@user = User.find_or_initialize_by(email: user_params[:email])
|
10
|
+
@user.update(user_params)
|
11
|
+
|
12
|
+
if user.errors.blank?
|
13
|
+
save_configurations!
|
14
|
+
redirect_to :root
|
15
|
+
else
|
16
|
+
render 'index'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
|
23
|
+
def user_params
|
24
|
+
params.require(:user).permit(:email, :password, :password_confirmation)
|
25
|
+
end
|
26
|
+
|
27
|
+
def user
|
28
|
+
@user ||= User.new
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class OnboardingController < ApplicationController
|
2
|
+
|
3
|
+
def index
|
4
|
+
if File.exist?(Rails.application.paths['config/secrets'].expanded.last)
|
5
|
+
render 'complete' and return
|
6
|
+
end
|
7
|
+
render 'welcome'
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def save_configurations!
|
13
|
+
File.open(Rails.application.paths['config/secrets'].expanded.last, 'w') do |file|
|
14
|
+
config = ActiveRecord::Base.configurations
|
15
|
+
config['development']['secret_key_base'] = config['production']['secret_key'] = Rails.application.secrets.secret_key_base
|
16
|
+
file.write(config.to_yaml)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class SessionsController < ApplicationController
|
2
|
+
before_action :authenticate!, except: [:failed, :new]
|
3
|
+
|
4
|
+
def create
|
5
|
+
redirect_to :root
|
6
|
+
end
|
7
|
+
|
8
|
+
def destroy
|
9
|
+
warden.logout
|
10
|
+
redirect_to :back
|
11
|
+
end
|
12
|
+
|
13
|
+
def failed
|
14
|
+
respond_to do |format|
|
15
|
+
format.html do
|
16
|
+
render 'new'
|
17
|
+
end
|
18
|
+
format.js do
|
19
|
+
render 'show' and return
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Admin
|
2
|
+
class ImageBuilder < ActionView::Helpers::FormBuilder
|
3
|
+
|
4
|
+
def message
|
5
|
+
if object.header?
|
6
|
+
content_tag :p, "You can replace your header by either <strong>clicking</strong> or <strong>dropping</strong> a picture here.".html_safe
|
7
|
+
else
|
8
|
+
content_tag :p, "Upload a picture for your post' header by either <strong>clicking</strong> or <strong>dropping</strong> a picture here".html_safe
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def t(*args)
|
15
|
+
args.push({}) unless args.last.is_a?(Hash)
|
16
|
+
args.last[:scope] = %w(admin form image)
|
17
|
+
I18n.t *args
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(method, *args, &block)
|
21
|
+
@template.send(method, *args, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Admin
|
2
|
+
class PartialBuilder < ActionView::Helpers::FormBuilder
|
3
|
+
|
4
|
+
def errors
|
5
|
+
return unless object.errors.any?
|
6
|
+
content_tag :div, class: %w(container errors) do
|
7
|
+
[
|
8
|
+
content_tag(:span, h(object.errors.full_messages.to_sentence)),
|
9
|
+
link_to("x", "javascript:void(0)", class: %w(dismiss button))
|
10
|
+
].join.html_safe
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def title
|
15
|
+
content_tag :div, id: "partial_title_wrapper", class: %w(title wrapper) do
|
16
|
+
[
|
17
|
+
text_field(:title, placeholder: t('.title'), class: %w(input)),
|
18
|
+
possible_actions
|
19
|
+
].join.html_safe
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def editor
|
24
|
+
[
|
25
|
+
editor_options,
|
26
|
+
content_tag(:div, class: %w(main editor)) do
|
27
|
+
[
|
28
|
+
editor_content,
|
29
|
+
content_tag(:div, preview, id: "editorSideContent")
|
30
|
+
].join.html_safe
|
31
|
+
end
|
32
|
+
].join.html_safe
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def preview
|
38
|
+
content_tag(:div, id: 'contentPreviewContainer') do
|
39
|
+
[
|
40
|
+
content_tag(:style),
|
41
|
+
content_tag(:script, nil, class: %w(preview), type: 'text/javascript'),
|
42
|
+
content_tag(:article, nil, class: %w(content preview)),
|
43
|
+
].join.html_safe
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def editor_options
|
48
|
+
content_tag :div, class: %w(editor options wrapper) do
|
49
|
+
Options.new(@template).render
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def editor_content
|
54
|
+
content_tag :div, class: %w(content wrapper) do
|
55
|
+
[
|
56
|
+
text_area(:content, placeholder: t('.content'), class: %w(content editor)),
|
57
|
+
text_area(:stylesheet, placeholder: t('.stylesheet'), class: %w(stylesheet hidden editor)),
|
58
|
+
text_area(:javascript, placeholder: t('.javascript'), class: %w(javascript hidden editor))
|
59
|
+
].join.html_safe
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def possible_actions
|
64
|
+
content_tag :div, class: %w(possible save actions) do
|
65
|
+
content_tag(:div, save_button, class: %w(wrapper standalone))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def save_button
|
70
|
+
button("Save", name: "post[status]", value: "draft", class: %w(button))
|
71
|
+
end
|
72
|
+
|
73
|
+
def method_missing(method, *args, &block)
|
74
|
+
@template.send(method, *args, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
class Options
|
78
|
+
|
79
|
+
def initialize(template)
|
80
|
+
@template = template
|
81
|
+
end
|
82
|
+
|
83
|
+
def render
|
84
|
+
content_tag(:div, editor_options, class: %w(editor options))
|
85
|
+
end
|
86
|
+
|
87
|
+
def editor_options
|
88
|
+
[
|
89
|
+
content_tag(:a, t('fields.text'), binding: ".editor.content", class: %w(content active)),
|
90
|
+
content_tag(:a, t('fields.CSS'), binding: ".editor.stylesheet", class: %w(content)),
|
91
|
+
content_tag(:a, t('fields.JS'), binding: ".editor.javascript", class: %w(content))
|
92
|
+
].join.html_safe
|
93
|
+
end
|
94
|
+
|
95
|
+
def t(*args)
|
96
|
+
I18n.t args[0], scope: %w(admin partials form options)
|
97
|
+
end
|
98
|
+
|
99
|
+
def method_missing(method, *args, &block)
|
100
|
+
@template.send(method, *args, &block)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Admin
|
2
|
+
class PostBuilder < ActionView::Helpers::FormBuilder
|
3
|
+
|
4
|
+
def initialize(object_name, object, template, options)
|
5
|
+
if object.draft?
|
6
|
+
options[:html][:class] << 'autosave'
|
7
|
+
end
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def errors
|
12
|
+
return unless object.errors.any?
|
13
|
+
content_tag :div, class: %w(container errors) do
|
14
|
+
[
|
15
|
+
content_tag(:span, h(object.errors.full_messages.to_sentence)),
|
16
|
+
link_to("x", "javascript:void(0)", class: %w(dismiss button))
|
17
|
+
].join.html_safe
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def editor
|
22
|
+
content_tag :section, class: %w(textareas) do
|
23
|
+
[
|
24
|
+
text_area(:content, placeholder: t('.content'), class: %w(content active), target: 'content'),
|
25
|
+
text_area(:stylesheet, placeholder: t('.stylesheet'), class: %w(stylesheet), target: 'stylesheet'),
|
26
|
+
text_area(:javascript, placeholder: t('.javascript'), class: %w(javascript), target: 'javascript')
|
27
|
+
].join.html_safe
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def action
|
32
|
+
if object.published?
|
33
|
+
button 'Save', value: 'save', form: "postEditor"
|
34
|
+
else
|
35
|
+
button 'Publish', value: 'publish', form: "postEditor"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def t(*args)
|
40
|
+
I18n.t args[0], scope: %w(admin form post)
|
41
|
+
end
|
42
|
+
|
43
|
+
def method_missing(method, *args, &block)
|
44
|
+
@template.send(method, *args, &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Admin
|
2
|
+
module ImagesHelper
|
3
|
+
|
4
|
+
def image_form_signature(policy)
|
5
|
+
@signature ||= begin
|
6
|
+
key = Rails.application.secrets.s3['secret_key']
|
7
|
+
sha = OpenSSL::Digest.new('sha1')
|
8
|
+
digest = OpenSSL::HMAC.digest sha, key, policy
|
9
|
+
Base64.encode64(digest).gsub("\n", "")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def image_form_policy(post)
|
14
|
+
@policy ||= begin
|
15
|
+
namespace = [post.id]
|
16
|
+
if Rails.application.secrets.s3.has_key?('namespace')
|
17
|
+
namespace.insert 0, Rails.application.secrets.s3['namespace']
|
18
|
+
end
|
19
|
+
|
20
|
+
policy = {
|
21
|
+
"expiration" => (Time.now + 10.years).utc.to_s(:iso8601),
|
22
|
+
"conditions" => [
|
23
|
+
{"bucket" => Rails.application.secrets.s3['bucket']},
|
24
|
+
["starts-with", "$key", "#{namespace.join('/')}/"],
|
25
|
+
["starts-with", "$Content-Type", ""],
|
26
|
+
{"acl" => "private"},
|
27
|
+
{'success_action_status' => '201'}
|
28
|
+
]
|
29
|
+
}
|
30
|
+
Base64.encode64(policy.to_json).gsub("\n","")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def editor_image_tag(post)
|
35
|
+
return unless post.header?
|
36
|
+
content_tag :div, class: %w(image), style: "background-image: url('#{post.header.url}')" do
|
37
|
+
button_to "Remove this image",
|
38
|
+
admin_post_properties_path(post.id),
|
39
|
+
method: :delete,
|
40
|
+
remote: true,
|
41
|
+
params: {
|
42
|
+
property: 'image'
|
43
|
+
},
|
44
|
+
data: {confirm: 'Are you sure you want to destroy this image?'}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def images_config_title
|
49
|
+
if @s3 && @s3.errors.any?
|
50
|
+
content_tag :h1, class: %w(error) do
|
51
|
+
@s3.errors.messages.values.flatten.to_sentence
|
52
|
+
end
|
53
|
+
else
|
54
|
+
content_tag :h1 do
|
55
|
+
t('admin.images.helper.title')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Admin::LabelsHelper
|
2
|
+
def create_label_button(label, post)
|
3
|
+
button_to label.name.capitalize,
|
4
|
+
admin_post_properties_path(post.id),
|
5
|
+
remote: true,
|
6
|
+
form: {id: "label-#{label.id}"},
|
7
|
+
form_class: %w(create label),
|
8
|
+
params: {
|
9
|
+
property: :label,
|
10
|
+
value: label.name
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def destroy_label_button(label, post)
|
15
|
+
button_to label.name.capitalize,
|
16
|
+
admin_post_properties_path(post.id),
|
17
|
+
form: {id: "label-#{label.id}"},
|
18
|
+
form_class: %w(destroy label),
|
19
|
+
method: :delete,
|
20
|
+
remote: true,
|
21
|
+
params: {
|
22
|
+
property: :label,
|
23
|
+
value: label.name
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Admin
|
2
|
+
module PostsHelper
|
3
|
+
include ::PostsHelper
|
4
|
+
|
5
|
+
def post_edit_content(post)
|
6
|
+
content_tag :div, id: 'PostBody', postid: @post.id,
|
7
|
+
class: %w(content),
|
8
|
+
as: 'Editor.Content',
|
9
|
+
contenteditable: true,
|
10
|
+
href: admin_post_path(@post.id) do |div|
|
11
|
+
|
12
|
+
if Rails.application.secrets.has_key?(:s3)
|
13
|
+
div[:bucket] = Rails.application.secrets.s3['bucket'],
|
14
|
+
div[:access_key] = Rails.application.secrets.s3['access_key'],
|
15
|
+
div[:signature] = image_form_signature(image_form_policy(@post)),
|
16
|
+
div[:policy] = image_form_policy(@post)
|
17
|
+
if Rails.application.secrets.s3.has_key?('namespace')
|
18
|
+
div['namespace'] = Rails.application.secrets.s3['namespace']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
post.content
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module ApplicationHelper
|
2
|
+
def admin_navigation
|
3
|
+
return unless signed_in?
|
4
|
+
render 'sessions/navigation'
|
5
|
+
end
|
6
|
+
|
7
|
+
def title_tag(title = 'Ecrire')
|
8
|
+
content_tag :title do
|
9
|
+
if block_given?
|
10
|
+
yield
|
11
|
+
elsif !@post.nil?
|
12
|
+
@post.title
|
13
|
+
else
|
14
|
+
title
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def assets_tags
|
20
|
+
[
|
21
|
+
stylesheet_link_tag("application", "base", media: "all", "data-turbolinks-track" => true),
|
22
|
+
javascript_include_tag("application", "base", "data-turbolinks-track" => true)
|
23
|
+
].join.html_safe
|
24
|
+
end
|
25
|
+
|
26
|
+
def meta_informations_tags
|
27
|
+
[
|
28
|
+
content_tag(:link, nil, rel: 'alternate', type: 'application/rss+xml', title: 'RSS', href: '/feed'),
|
29
|
+
content_tag(:link, nil, rel: %w(shortcut icon), href: asset_url('favicon.ico')),
|
30
|
+
csrf_meta_tags
|
31
|
+
].join.html_safe
|
32
|
+
end
|
33
|
+
|
34
|
+
def description_meta_tag
|
35
|
+
if Rails.application.secrets.fetch(:meta, {}).has_key?(:description)
|
36
|
+
content_tag :meta, nil, name: 'description', content: Rails.application.secrets[:meta][:description]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def open_graph_type
|
41
|
+
if @post.nil?
|
42
|
+
'website'
|
43
|
+
else
|
44
|
+
'article'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def body_tag(html_options = {}, &block)
|
49
|
+
html_options[:id] ||= [controller_name, action_name].map(&:capitalize).join
|
50
|
+
content_tag :body, html_options, &block
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def flash_messages
|
55
|
+
return if flash.empty?
|
56
|
+
|
57
|
+
flash.map do |name, msg|
|
58
|
+
content_tag :div, class: %W(flash #{name}) do
|
59
|
+
content_tag(:span, h(msg), class: %w(message))
|
60
|
+
end
|
61
|
+
end.join.html_safe
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module ContentTagHelper
|
2
|
+
def content_tag(*args, &block)
|
3
|
+
if block_given?
|
4
|
+
tag = Tag.new(*args)
|
5
|
+
old_buf = @output_buffer
|
6
|
+
@output_buffer = ActionView::OutputBuffer.new
|
7
|
+
value = yield(tag)
|
8
|
+
content = tag.render(@output_buffer.presence || value)
|
9
|
+
@output_buffer = old_buf
|
10
|
+
content
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
class Tag
|
19
|
+
include ActionView::Helpers::CaptureHelper
|
20
|
+
attr_accessor :id
|
21
|
+
attr_reader :name, :css
|
22
|
+
|
23
|
+
def initialize(name, *args)
|
24
|
+
@name = name
|
25
|
+
@attributes = tag_options(*args)
|
26
|
+
@attributes[:class] = Tag::CSS.new(@attributes.fetch(:class, {}))
|
27
|
+
end
|
28
|
+
|
29
|
+
def tag_options(*args)
|
30
|
+
options = nil
|
31
|
+
args.each do |a|
|
32
|
+
if a.is_a?(Hash)
|
33
|
+
options = a
|
34
|
+
break
|
35
|
+
end
|
36
|
+
end
|
37
|
+
(options || {}).with_indifferent_access
|
38
|
+
end
|
39
|
+
|
40
|
+
def css
|
41
|
+
@attributes[:class]
|
42
|
+
end
|
43
|
+
|
44
|
+
def []=(k,v)
|
45
|
+
@attributes[k] = v
|
46
|
+
end
|
47
|
+
|
48
|
+
def render(content)
|
49
|
+
"<#{name}#{render_attributes}>#{content.to_s.strip}</#{name}>".html_safe
|
50
|
+
end
|
51
|
+
|
52
|
+
def render_attributes
|
53
|
+
attrs = @attributes.dup
|
54
|
+
if css.empty?
|
55
|
+
attrs.delete :class
|
56
|
+
else
|
57
|
+
attrs[:class] = css.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
attrs.keys.map do |k|
|
61
|
+
"#{k}='#{attrs[k]}'"
|
62
|
+
end.join(' ').prepend(' ').html_safe
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
class CSS
|
67
|
+
|
68
|
+
def initialize(css)
|
69
|
+
if css.is_a? String
|
70
|
+
@internals = css.split(' ')
|
71
|
+
else
|
72
|
+
@internals = css.to_a
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
@internals.uniq.join(' ').html_safe
|
78
|
+
end
|
79
|
+
|
80
|
+
def empty?
|
81
|
+
@internals.empty?
|
82
|
+
end
|
83
|
+
|
84
|
+
def <<(name)
|
85
|
+
@internals << name
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module OpenGraphHelper
|
2
|
+
# OpenGraph is in meta tags. First I thought it would bring problem if meta tags wouldn't change between page load.
|
3
|
+
# Thinking it through, it doesn't matter if open graph tags aren't changed between pages as it's needed by crawler that does full page load
|
4
|
+
# So the tags will always match the content.
|
5
|
+
# I doubt this will change in the future as turbolinks checks for crawlers and disable itself when it meets one.
|
6
|
+
#
|
7
|
+
|
8
|
+
def open_graph_tags
|
9
|
+
if @post.nil?
|
10
|
+
og_website
|
11
|
+
else
|
12
|
+
og_article(@post)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def og_website
|
19
|
+
[
|
20
|
+
og_title,
|
21
|
+
og_type('website')
|
22
|
+
].join.html_safe
|
23
|
+
end
|
24
|
+
|
25
|
+
def og_article(post)
|
26
|
+
raise OGNoArticleError if post.nil?
|
27
|
+
[
|
28
|
+
og_title,
|
29
|
+
og_type('article'),
|
30
|
+
content_tag(:meta, nil, property: 'og:article:published_time', content: post.published_at.iso8601)
|
31
|
+
].join.html_safe
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def og_type(value)
|
36
|
+
content_tag :meta, nil, property: 'og:type', content: value
|
37
|
+
end
|
38
|
+
|
39
|
+
def og_title
|
40
|
+
content_tag :meta, nil, property: 'og:title', content: title
|
41
|
+
end
|
42
|
+
|
43
|
+
class OGNoArticleError < StandardError; end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module PostsHelper
|
2
|
+
def post_path(post, options = {})
|
3
|
+
if post.published?
|
4
|
+
options[:year] = post.published_at.year
|
5
|
+
options[:month] = post.published_at.month
|
6
|
+
else
|
7
|
+
options[:year] = post.created_at.year
|
8
|
+
options[:month] = post.created_at.month
|
9
|
+
end
|
10
|
+
|
11
|
+
super(post.becomes(::Post), options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def edit_post_link(options = {})
|
15
|
+
return unless signed_in?
|
16
|
+
|
17
|
+
link_to t('posts.edit'), edit_admin_post_path(post.id), options
|
18
|
+
end
|
19
|
+
end
|