storytime 2.1.6 → 2.1.7
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.
- checksums.yaml +5 -5
- data/.github/workflows/test.yml +54 -0
- data/.gitignore +2 -1
- data/.ruby-version +1 -1
- data/.tool-versions +1 -0
- data/Gemfile +5 -3
- data/Gemfile.lock +414 -425
- data/Guardfile +1 -1
- data/app/assets/fonts/storytime-icons.eot +0 -0
- data/app/assets/fonts/storytime-icons.svg +23 -0
- data/app/assets/fonts/storytime-icons.ttf +0 -0
- data/app/assets/fonts/storytime-icons.woff +0 -0
- data/app/assets/javascripts/storytime/application.js +1 -8
- data/app/assets/javascripts/storytime/off_canvas.coffee +16 -0
- data/app/assets/javascripts/storytime/wysiwyg.js.coffee +9 -7
- data/app/assets/stylesheets/storytime/_buttons.scss +33 -0
- data/app/assets/stylesheets/storytime/_list-group.scss +1 -1
- data/app/assets/stylesheets/storytime/application.scss +14 -2
- data/app/assets/stylesheets/storytime/icons.scss +5 -5
- data/app/assets/stylesheets/storytime/leather/_buttons.scss +31 -0
- data/app/assets/stylesheets/storytime/leather/_devise.scss +72 -0
- data/app/assets/stylesheets/storytime/leather/_grid.scss +19 -0
- data/app/assets/stylesheets/storytime/leather/_list_groups.scss +33 -0
- data/app/assets/stylesheets/storytime/leather/_nav_menus.scss +125 -0
- data/app/assets/stylesheets/storytime/leather/_navbar_transparent.scss +23 -0
- data/app/assets/stylesheets/storytime/leather/_off_canvas.scss +109 -0
- data/app/assets/stylesheets/storytime/leather/_scroll_panels.scss +85 -0
- data/app/assets/stylesheets/storytime/leather/_toggle_columns.scss +23 -0
- data/app/assets/stylesheets/storytime/leather/_typography.scss +12 -0
- data/app/assets/stylesheets/storytime/leather/_utilities.scss +54 -0
- data/app/assets/stylesheets/storytime/leather/_variables.scss +8 -0
- data/app/assets/stylesheets/storytime/posts.scss +9 -1
- data/app/controllers/storytime/application_controller.rb +1 -1
- data/app/controllers/storytime/dashboard/blog_posts_controller.rb +5 -3
- data/app/controllers/storytime/dashboard/blogs_controller.rb +1 -1
- data/app/controllers/storytime/dashboard/media_controller.rb +4 -4
- data/app/controllers/storytime/dashboard/memberships_controller.rb +1 -1
- data/app/controllers/storytime/dashboard/pages_controller.rb +26 -6
- data/app/controllers/storytime/dashboard/posts_controller.rb +30 -5
- data/app/controllers/storytime/dashboard/subscriptions_controller.rb +1 -1
- data/app/controllers/storytime/pages_controller.rb +31 -1
- data/app/controllers/storytime/posts_controller.rb +1 -1
- data/app/controllers/storytime/subscriptions_controller.rb +5 -1
- data/app/helpers/storytime/application_helper.rb +0 -4
- data/app/models/concerns/storytime/post_featured_images.rb +2 -2
- data/app/models/concerns/storytime/post_partial_inheritance.rb +2 -2
- data/app/models/storytime/autosave.rb +1 -1
- data/app/models/storytime/comment.rb +1 -1
- data/app/models/storytime/media.rb +1 -1
- data/app/models/storytime/membership.rb +2 -2
- data/app/models/storytime/post.rb +7 -3
- data/app/models/storytime/site.rb +4 -6
- data/app/models/storytime/snippet.rb +12 -1
- data/app/models/storytime/subscription.rb +2 -2
- data/app/models/storytime/version.rb +1 -1
- data/app/policies/storytime/post_policy.rb +1 -1
- data/app/views/storytime/dashboard/_navigation.html.erb +0 -9
- data/app/views/storytime/dashboard/blog_posts/_form.html.erb +5 -1
- data/app/views/storytime/dashboard/blogs/edit.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/blogs/index.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/blogs/new.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/media/_gallery.html.erb +1 -1
- data/app/views/storytime/dashboard/media/_modal.html.erb +2 -2
- data/app/views/storytime/dashboard/media/show.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/memberships/_edit.html.erb +1 -1
- data/app/views/storytime/dashboard/memberships/_index.html.erb +3 -3
- data/app/views/storytime/dashboard/memberships/_new.html.erb +1 -1
- data/app/views/storytime/dashboard/memberships/edit.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/memberships/index.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/memberships/new.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/memberships/save.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/pages/_form.html.erb +1 -1
- data/app/views/storytime/dashboard/posts/_directory.html.erb +18 -0
- data/app/views/storytime/dashboard/posts/_form.html.erb +1 -1
- data/app/views/storytime/dashboard/posts/_list.html.erb +2 -26
- data/app/views/storytime/dashboard/posts/_new_button.html.erb +1 -1
- data/app/views/storytime/dashboard/posts/_post.html.erb +28 -0
- data/app/views/storytime/dashboard/posts/_sorts.html.erb +21 -0
- data/app/views/storytime/dashboard/posts/index.html.erb +5 -3
- data/app/views/storytime/dashboard/roles/_form.html.erb +1 -1
- data/app/views/storytime/dashboard/roles/edit.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/sites/_form.html.erb +1 -1
- data/app/views/storytime/dashboard/sites/site.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/snippets/_index.html.erb +1 -1
- data/app/views/storytime/dashboard/snippets/edit.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/snippets/index.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/snippets/new.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/subscriptions/_form.html.erb +1 -1
- data/app/views/storytime/dashboard/subscriptions/_index.html.erb +2 -2
- data/app/views/storytime/dashboard/subscriptions/form.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/subscriptions/index.json.jbuilder +1 -1
- data/app/views/storytime/dashboard/versions/_versions_info.html.erb +1 -1
- data/app/views/storytime/posts/show.html.erb +6 -0
- data/app/views/storytime/sites/_google_analytics_code.html.erb +5 -8
- data/config/initializers/assets.rb +2 -1
- data/config/initializers/friendly_id.rb +1 -1
- data/config/initializers/url_for_patch.rb +19 -8
- data/config/locales/devise.zh-CN.yml +59 -0
- data/config/locales/kaminari.zh-CN.yml +17 -0
- data/config/locales/simple_form.zh-CN.yml +26 -0
- data/config/locales/zh-CN.yml +141 -0
- data/config/routes.rb +2 -4
- data/db/migrate/20140501174341_create_storytime_posts.rb +1 -1
- data/db/migrate/20140509191309_create_friendly_id_slugs.rb +1 -1
- data/db/migrate/20140511200849_create_storytime_media.rb +1 -1
- data/db/migrate/20140513161233_create_storytime_sites.rb +1 -1
- data/db/migrate/20140514200234_create_storytime_tags.rb +1 -1
- data/db/migrate/20140514200304_create_storytime_taggings.rb +1 -1
- data/db/migrate/20140516141252_create_storytime_versions.rb +1 -1
- data/db/migrate/20140521190606_create_storytime_roles.rb +1 -1
- data/db/migrate/20140521191048_add_storytime_role_id_to_users.rb +1 -1
- data/db/migrate/20140521191728_create_storytime_permissions.rb +1 -1
- data/db/migrate/20140521191744_create_storytime_actions.rb +1 -1
- data/db/migrate/20140813014447_create_storytime_comments.rb +1 -1
- data/db/migrate/20140813130534_add_storytime_name_to_users.rb +1 -1
- data/db/migrate/20140916183056_create_storytime_autosaves.rb +1 -1
- data/db/migrate/20141020213343_add_secondary_media_id_to_storytime_post.rb +1 -1
- data/db/migrate/20141021073356_create_storytime_snippets.rb +1 -1
- data/db/migrate/20141111164439_create_storytime_subscriptions.rb +1 -1
- data/db/migrate/20150122200805_add_title_and_content_index_to_storytime_post.rb +1 -1
- data/db/migrate/20150128185746_seed_new_actions_and_permissions.rb +1 -1
- data/db/migrate/20150129215308_add_site_id_to_storytime_subscription.rb +1 -1
- data/db/migrate/20150206201847_add_site_id_to_storytime_post.rb +1 -1
- data/db/migrate/20150206201919_add_site_id_to_storytime_snippet.rb +1 -1
- data/db/migrate/20150206201931_add_site_id_to_storytime_tag.rb +1 -1
- data/db/migrate/20150206205256_add_notification_fields_to_storytime_post.rb +1 -1
- data/db/migrate/20150216211257_add_subdomain_to_storytime_sites.rb +1 -1
- data/db/migrate/20150216225045_add_site_to_storytime_media.rb +1 -1
- data/db/migrate/20150219210528_remove_root_page_content_from_storytime_sites.rb +1 -1
- data/db/migrate/20150220184902_add_blog_id_to_posts.rb +1 -1
- data/db/migrate/20150224192138_add_homepage_path_to_storytime_sites.rb +1 -1
- data/db/migrate/20150224193151_add_subscription_email_from_to_storytime_sites.rb +1 -1
- data/db/migrate/20150224193551_add_layout_to_storytime_sites.rb +1 -1
- data/db/migrate/20150224194559_add_disqus_forum_shortname_to_storytime_sites.rb +1 -1
- data/db/migrate/20150224212453_remove_homepage_path_from_storytime_sites.rb +1 -1
- data/db/migrate/20150225143516_add_site_id_to_storytime_autosaves.rb +1 -1
- data/db/migrate/20150225143826_add_site_id_to_storytime_comments.rb +1 -1
- data/db/migrate/20150225145119_add_site_id_to_storytime_versions.rb +1 -1
- data/db/migrate/20150225145316_add_site_id_to_storytime_taggings.rb +1 -1
- data/db/migrate/20150225145608_update_storytime_site_id_columns.rb +1 -1
- data/db/migrate/20150225164232_add_site_id_to_storytime_permissions.rb +1 -1
- data/db/migrate/20150225212917_create_storytime_memberships.rb +1 -1
- data/db/migrate/20150225213535_create_memberships_for_storytime_users.rb +1 -1
- data/db/migrate/20150226201739_add_custom_domain_to_storytime_sites.rb +1 -1
- data/db/migrate/20150302171500_add_site_id_to_storytime_media.rb +1 -1
- data/db/migrate/20150302171722_set_site_layout.rb +1 -1
- data/db/migrate/20150302185138_remove_storytime_role_id_from_users.rb +1 -1
- data/db/migrate/20150302192525_transfer_posts_to_blogs.rb +1 -1
- data/db/migrate/20150302192759_seed_permissions.rb +1 -1
- data/db/migrate/20150331162329_add_discourse_name_to_storytime_sites.rb +1 -1
- data/db/migrate/20150402161427_remove_subdomain_from_storytime_site.rb +1 -1
- data/db/migrate/20150520181115_create_storytime_navigations.rb +1 -1
- data/db/migrate/20150520185227_create_storytime_links.rb +1 -1
- data/db/migrate/20150520190700_add_position_to_storytime_links.rb +1 -1
- data/db/migrate/20150529192058_add_url_to_storytime_links.rb +1 -1
- data/db/migrate/20260408001637_add_canonical_url_to_storytime_posts.rb +5 -0
- data/db/migrate/20260701000000_sanitize_existing_storytime_snippets.rb +22 -0
- data/lib/storytime/cli/install.rb +2 -20
- data/lib/storytime/concerns/action_controller_extension.rb +36 -0
- data/lib/storytime/constraints/page_constraint.rb +8 -2
- data/lib/storytime/engine.rb +3 -5
- data/lib/storytime/migrators/v1.rb +3 -3
- data/lib/storytime/post_notifier.rb +1 -1
- data/lib/storytime/post_url_handler.rb +18 -5
- data/lib/storytime/storytime_helpers.rb +4 -0
- data/lib/storytime/version.rb +1 -1
- data/lib/storytime.rb +1 -1
- data/spec/controllers/dashboard_controller_spec.rb +5 -6
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/config/database.yml +3 -3
- data/spec/dummy/config/initializers/devise.rb +1 -1
- data/spec/dummy/db/migrate/20140530185250_devise_create_users.rb +1 -1
- data/spec/dummy/db/migrate/20150127172846_create_widgets.rb +1 -1
- data/spec/dummy/db/migrate/20150206203824_add_video_url_to_storytime_posts.rb +1 -1
- data/spec/dummy/db/schema.rb +226 -244
- data/spec/factories/action_factories.rb +3 -3
- data/spec/factories/comment_factories.rb +1 -1
- data/spec/factories/media_factories.rb +1 -1
- data/spec/factories/membership_factories.rb +1 -1
- data/spec/factories/navigation_factories.rb +3 -3
- data/spec/factories/permission_factories.rb +1 -1
- data/spec/factories/post_factories.rb +2 -2
- data/spec/factories/role_factories.rb +11 -11
- data/spec/factories/site_factories.rb +3 -3
- data/spec/factories/snippet_factories.rb +1 -1
- data/spec/factories/subscription_factories.rb +1 -1
- data/spec/factories/user_factories.rb +2 -2
- data/spec/factories/widget_factories.rb +2 -2
- data/spec/features/blogs_spec.rb +7 -7
- data/spec/features/comments_spec.rb +11 -11
- data/spec/features/dashboard/media_spec.rb +17 -11
- data/spec/features/dashboard/memberships_spec.rb +13 -19
- data/spec/features/dashboard/navigations_spec.rb +1 -1
- data/spec/features/dashboard/pages_spec.rb +8 -8
- data/spec/features/dashboard/posts_spec.rb +19 -19
- data/spec/features/dashboard/sites_spec.rb +1 -1
- data/spec/features/dashboard/snippets_spec.rb +3 -3
- data/spec/features/dashboard/subscription_spec.rb +2 -2
- data/spec/features/pages_spec.rb +3 -3
- data/spec/features/posts_spec.rb +2 -2
- data/spec/features/subscription_spec.rb +3 -3
- data/spec/importers/wordpress_spec.rb +1 -1
- data/spec/lib/mysql_fulltext_search_adapter_spec.rb +3 -3
- data/spec/lib/mysql_search_adapter_spec.rb +3 -3
- data/spec/lib/postgres_search_adapter_spec.rb +3 -3
- data/spec/lib/sqlite3_search_adapter_spec.rb +3 -3
- data/spec/lib/storytime/constraints/page_constraint_spec.rb +40 -0
- data/spec/lib/storytime_helpers_spec.rb +2 -2
- data/spec/models/navigation_spec.rb +3 -3
- data/spec/models/post_spec.rb +29 -29
- data/spec/models/snippet_spec.rb +31 -0
- data/spec/models/subscription_spec.rb +4 -4
- data/spec/models/tagging_spec.rb +14 -14
- data/spec/models/version_spec.rb +29 -29
- data/spec/policies/comment_policy_spec.rb +11 -11
- data/spec/policies/post_policy_spec.rb +13 -13
- data/spec/requests/pages_spec.rb +37 -0
- data/spec/requests/routings_spec.rb +14 -15
- data/spec/spec_helper.rb +8 -15
- data/spec/support/domains.rb +2 -2
- data/spec/support/feature_macros.rb +5 -5
- data/spec/support/pundit_matcher.rb +3 -3
- data/storytime.gemspec +15 -20
- data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +195 -0
- data/vendor/assets/javascripts/codemirror/addons/edit/closetag.js +169 -0
- data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +182 -0
- data/vendor/assets/javascripts/codemirror.js +8922 -0
- data/vendor/assets/javascripts/medium-editor.min.js +3 -3
- data/vendor/assets/stylesheets/codemirror/themes/solarized.css +169 -0
- data/vendor/assets/stylesheets/codemirror.css +347 -0
- metadata +94 -134
- data/config/initializers/storytime_admin.rb +0 -5
- data/config/spring.rb +0 -1
- data/spec/dummy/app/controllers/storytime_admin/widgets_controller.rb +0 -5
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
|
@@ -2,8 +2,8 @@ require "spec_helper"
|
|
|
2
2
|
|
|
3
3
|
describe "Root path", type: :request do
|
|
4
4
|
it "routes to blog_homepage#show when site homepage is a blog" do
|
|
5
|
-
site =
|
|
6
|
-
user =
|
|
5
|
+
site = FactoryBot.create(:site)
|
|
6
|
+
user = FactoryBot.create(:admin)
|
|
7
7
|
site.save_with_seeds(user)
|
|
8
8
|
site.homepage = site.blogs.first
|
|
9
9
|
|
|
@@ -14,12 +14,11 @@ describe "Root path", type: :request do
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
it "routes to pages#show when site homepage is page" do
|
|
17
|
-
site =
|
|
18
|
-
user =
|
|
19
|
-
home_page =
|
|
17
|
+
site = FactoryBot.create(:site)
|
|
18
|
+
user = FactoryBot.create(:admin)
|
|
19
|
+
home_page = FactoryBot.create(:page, site: site)
|
|
20
20
|
site.save_with_seeds(user)
|
|
21
|
-
site.
|
|
22
|
-
site.save
|
|
21
|
+
site.update_attribute :root_post_id, home_page.id
|
|
23
22
|
|
|
24
23
|
get "/"
|
|
25
24
|
|
|
@@ -31,8 +30,8 @@ end
|
|
|
31
30
|
|
|
32
31
|
describe "Post path", type: :request do
|
|
33
32
|
it "uses /posts/post-slug when site#post_slug_style is default" do
|
|
34
|
-
site =
|
|
35
|
-
post =
|
|
33
|
+
site = FactoryBot.create(:site, post_slug_style: :default, custom_domain: "www.example.com")
|
|
34
|
+
post = FactoryBot.create(:post, site: site)
|
|
36
35
|
expect(storytime.post_path(post)).to eq("/posts/#{post.slug}")
|
|
37
36
|
|
|
38
37
|
get url_for([post, only_path: true])
|
|
@@ -43,8 +42,8 @@ describe "Post path", type: :request do
|
|
|
43
42
|
end
|
|
44
43
|
|
|
45
44
|
it "uses /year/month/day/post-slug when site#post_slug_style is day_and_name" do
|
|
46
|
-
site =
|
|
47
|
-
post =
|
|
45
|
+
site = FactoryBot.create(:site, post_slug_style: :day_and_name, custom_domain: "www.example.com")
|
|
46
|
+
post = FactoryBot.create(:post, site: site)
|
|
48
47
|
date = post.created_at.to_date
|
|
49
48
|
|
|
50
49
|
expect(url_for([post, only_path: true])).to eq("/#{date.year}/#{date.strftime('%m')}/#{date.strftime('%d')}/#{post.slug}")
|
|
@@ -57,8 +56,8 @@ describe "Post path", type: :request do
|
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
it "uses /year/month/post-slug when site#post_slug_style is month_and_name" do
|
|
60
|
-
site =
|
|
61
|
-
post =
|
|
59
|
+
site = FactoryBot.create(:site, post_slug_style: :month_and_name, custom_domain: "www.example.com")
|
|
60
|
+
post = FactoryBot.create(:post, site: site)
|
|
62
61
|
date = post.created_at.to_date
|
|
63
62
|
expect(url_for([post, only_path: true])).to eq("/#{date.year}/#{date.strftime('%m')}/#{post.slug}")
|
|
64
63
|
|
|
@@ -70,8 +69,8 @@ describe "Post path", type: :request do
|
|
|
70
69
|
end
|
|
71
70
|
|
|
72
71
|
it "uses /post-id when site#post_slug_style is post_id" do
|
|
73
|
-
site =
|
|
74
|
-
post =
|
|
72
|
+
site = FactoryBot.create(:site, post_slug_style: :post_id, custom_domain: "www.example.com")
|
|
73
|
+
post = FactoryBot.create(:post, site: site)
|
|
75
74
|
expect(url_for([post, only_path: true])).to eq("/posts/#{post.id}")
|
|
76
75
|
|
|
77
76
|
get url_for([post, only_path: true])
|
data/spec/spec_helper.rb
CHANGED
|
@@ -2,32 +2,25 @@
|
|
|
2
2
|
ENV["RAILS_ENV"] ||= 'test'
|
|
3
3
|
require File.expand_path("../dummy/config/environment", __FILE__)
|
|
4
4
|
require 'rspec/rails'
|
|
5
|
-
require '
|
|
6
|
-
require 'factory_girl_rails'
|
|
5
|
+
require 'factory_bot_rails'
|
|
7
6
|
require 'capybara/rails'
|
|
8
7
|
require 'capybara/rspec'
|
|
9
|
-
require 'capybara/
|
|
8
|
+
require 'capybara/cuprite'
|
|
10
9
|
require "pundit/rspec"
|
|
11
10
|
|
|
12
11
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|
13
12
|
|
|
14
13
|
# Checks for pending migrations before tests are run.
|
|
15
14
|
# If you are not using ActiveRecord, you can remove this line.
|
|
15
|
+
# require "pry-byebug"
|
|
16
|
+
# binding.pry
|
|
16
17
|
ActiveRecord::Migration.maintain_test_schema!
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# inspector: true,
|
|
21
|
-
# debug: true,
|
|
22
|
-
phantomjs_options: ['--load-images=no', '--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1'],
|
|
23
|
-
js_errors: false
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
Capybara.register_driver :poltergeist_st do |app|
|
|
27
|
-
Capybara::Poltergeist::Driver.new(app, poltergeist_options)
|
|
19
|
+
Capybara.register_driver :cuprite do |app|
|
|
20
|
+
Capybara::Cuprite::Driver.new(app, js_errors: false, headless: true)
|
|
28
21
|
end
|
|
29
22
|
|
|
30
|
-
Capybara.javascript_driver = :
|
|
23
|
+
Capybara.javascript_driver = :cuprite
|
|
31
24
|
|
|
32
25
|
RSpec.configure do |config|
|
|
33
26
|
|
|
@@ -79,7 +72,7 @@ RSpec.configure do |config|
|
|
|
79
72
|
|
|
80
73
|
config.include FeatureMacros, type: :feature
|
|
81
74
|
config.include Storytime::Engine.routes.url_helpers
|
|
82
|
-
config.include Devise::
|
|
75
|
+
config.include Devise::Test::ControllerHelpers, type: :controller
|
|
83
76
|
|
|
84
77
|
config.filter_run focus: true
|
|
85
78
|
config.run_all_when_everything_filtered = true
|
data/spec/support/domains.rb
CHANGED
|
@@ -2,13 +2,13 @@ RSpec.configure do |config|
|
|
|
2
2
|
Capybara.always_include_port = true
|
|
3
3
|
|
|
4
4
|
config.before(type: :feature) do
|
|
5
|
-
@current_site ||=
|
|
5
|
+
@current_site ||= FactoryBot.build(:site)
|
|
6
6
|
set_domain @current_site.custom_domain
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
config.before(type: :controller) do
|
|
10
10
|
@request.env["devise.mapping"] = Devise.mappings[:user]
|
|
11
|
-
@current_site ||=
|
|
11
|
+
@current_site ||= FactoryBot.create(:site)
|
|
12
12
|
@request.host = @current_site.custom_domain
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module FeatureMacros
|
|
2
2
|
def login(user = nil, skip_site = false)
|
|
3
|
-
user ||=
|
|
3
|
+
user ||= FactoryBot.create(:user)
|
|
4
4
|
unless skip_site
|
|
5
5
|
setup_site(user)
|
|
6
6
|
set_domain(@current_site.custom_domain)
|
|
@@ -18,15 +18,15 @@ module FeatureMacros
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def login_admin(admin = nil)
|
|
21
|
-
login
|
|
21
|
+
login FactoryBot.create(:admin)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def login_editor(editor = nil)
|
|
25
|
-
login
|
|
25
|
+
login FactoryBot.create(:editor)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def login_writer(writer = nil)
|
|
29
|
-
login
|
|
29
|
+
login FactoryBot.create(:writer)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def current_user
|
|
@@ -38,7 +38,7 @@ module FeatureMacros
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def setup_site(user)
|
|
41
|
-
@current_site ||=
|
|
41
|
+
@current_site ||= FactoryBot.create(:site)
|
|
42
42
|
@current_site.save_with_seeds(user)
|
|
43
43
|
@current_site.homepage = @current_site.blogs.first
|
|
44
44
|
@current_site.save
|
|
@@ -3,11 +3,11 @@ RSpec::Matchers.define :permit! do |action|
|
|
|
3
3
|
policy.public_send("#{action}?")
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
failure_message do |policy|
|
|
7
7
|
"#{policy.class} does not permit #{action} on #{policy.record} for #{policy.user.inspect}."
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
failure_message_when_negated do |policy|
|
|
11
11
|
"#{policy.class} does not forbid #{action} on #{policy.record} for #{policy.user.inspect}."
|
|
12
12
|
end
|
|
13
|
-
end
|
|
13
|
+
end
|
data/storytime.gemspec
CHANGED
|
@@ -18,44 +18,39 @@ Gem::Specification.new do |s|
|
|
|
18
18
|
s.test_files = Dir["spec/**/*"] - Dir["spec/dummy/tmp/**/*"] - Dir["spec/dummy/log/*"] - Dir["spec/dummy/public/uploads/**/*"]
|
|
19
19
|
s.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
-
s.add_dependency "rails", ">=
|
|
22
|
-
s.add_dependency "pundit", ">= 0.
|
|
23
|
-
s.add_dependency "kaminari", ">= 0.
|
|
24
|
-
s.add_dependency "jbuilder", ">=
|
|
21
|
+
s.add_dependency "rails", ">= 7.0"
|
|
22
|
+
s.add_dependency "pundit", ">= 2.0.0"
|
|
23
|
+
s.add_dependency "kaminari", ">= 1.0.0"
|
|
24
|
+
s.add_dependency "jbuilder", ">= 2.0.0"
|
|
25
25
|
s.add_dependency "sass-rails", ">= 4.0"
|
|
26
26
|
s.add_dependency "bootstrap-sass", ">= 3.1"
|
|
27
27
|
s.add_dependency "coffee-rails", ">= 4.0"
|
|
28
28
|
s.add_dependency "jquery-rails", ">= 3.0"
|
|
29
29
|
s.add_dependency "simple_form", ">= 3.0"
|
|
30
30
|
s.add_dependency "friendly_id", ">= 5.0"
|
|
31
|
-
s.add_dependency "fog", ">=
|
|
32
|
-
s.add_dependency "carrierwave", ">=
|
|
31
|
+
s.add_dependency "fog-aws", ">= 3.0"
|
|
32
|
+
s.add_dependency "carrierwave", ">= 3.0"
|
|
33
33
|
s.add_dependency "mini_magick", ">= 3.7"
|
|
34
34
|
s.add_dependency "nokogiri", ">= 1.6"
|
|
35
|
-
s.add_dependency "font-awesome-sass", "
|
|
36
|
-
s.add_dependency "jquery-ui-rails", "
|
|
37
|
-
s.add_dependency "thor", "
|
|
38
|
-
s.add_dependency "leather", ">= 3.5"
|
|
39
|
-
s.add_dependency "codemirror-rails", ">=5.0"
|
|
40
|
-
s.add_dependency "storytime-admin", "~> 0.2"
|
|
35
|
+
s.add_dependency "font-awesome-sass", "<= 4.7.0"
|
|
36
|
+
s.add_dependency "jquery-ui-rails", ">= 6.0"
|
|
37
|
+
s.add_dependency "thor", ">= 0.19.1"
|
|
41
38
|
s.add_dependency "devise", ">= 3.2"
|
|
42
39
|
s.add_dependency "cocoon"
|
|
43
40
|
s.add_dependency "acts_as_list"
|
|
41
|
+
s.add_dependency "sprockets", ">= 3.7", "< 4.0"
|
|
44
42
|
|
|
45
43
|
s.add_development_dependency "pg"
|
|
46
44
|
s.add_development_dependency "rspec-rails"
|
|
47
45
|
s.add_development_dependency "capybara"
|
|
48
|
-
s.add_development_dependency "
|
|
49
|
-
s.add_development_dependency "
|
|
50
|
-
s.add_development_dependency "guard-rspec"
|
|
51
|
-
s.add_development_dependency "spring-commands-rspec"
|
|
52
|
-
s.add_development_dependency "spring", "1.1.3"
|
|
46
|
+
s.add_development_dependency "cuprite"
|
|
47
|
+
s.add_development_dependency "factory_bot_rails"
|
|
48
|
+
s.add_development_dependency "guard-rspec"
|
|
53
49
|
s.add_development_dependency "rb-fsevent"
|
|
54
|
-
s.add_development_dependency "
|
|
55
|
-
s.add_development_dependency "pry-stack_explorer"
|
|
50
|
+
s.add_development_dependency "debug"
|
|
56
51
|
s.add_development_dependency "database_cleaner"
|
|
57
52
|
s.add_development_dependency "better_errors"
|
|
58
53
|
s.add_development_dependency "binding_of_caller"
|
|
59
54
|
s.add_development_dependency "launchy"
|
|
60
|
-
s.add_development_dependency "
|
|
55
|
+
s.add_development_dependency "puma"
|
|
61
56
|
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
2
|
+
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
|
3
|
+
|
|
4
|
+
(function(mod) {
|
|
5
|
+
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
6
|
+
mod(require("../../lib/codemirror"));
|
|
7
|
+
else if (typeof define == "function" && define.amd) // AMD
|
|
8
|
+
define(["../../lib/codemirror"], mod);
|
|
9
|
+
else // Plain browser env
|
|
10
|
+
mod(CodeMirror);
|
|
11
|
+
})(function(CodeMirror) {
|
|
12
|
+
var defaults = {
|
|
13
|
+
pairs: "()[]{}''\"\"",
|
|
14
|
+
triples: "",
|
|
15
|
+
explode: "[]{}"
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
var Pos = CodeMirror.Pos;
|
|
19
|
+
|
|
20
|
+
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
|
|
21
|
+
if (old && old != CodeMirror.Init) {
|
|
22
|
+
cm.removeKeyMap(keyMap);
|
|
23
|
+
cm.state.closeBrackets = null;
|
|
24
|
+
}
|
|
25
|
+
if (val) {
|
|
26
|
+
cm.state.closeBrackets = val;
|
|
27
|
+
cm.addKeyMap(keyMap);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
function getOption(conf, name) {
|
|
32
|
+
if (name == "pairs" && typeof conf == "string") return conf;
|
|
33
|
+
if (typeof conf == "object" && conf[name] != null) return conf[name];
|
|
34
|
+
return defaults[name];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var bind = defaults.pairs + "`";
|
|
38
|
+
var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
|
|
39
|
+
for (var i = 0; i < bind.length; i++)
|
|
40
|
+
keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
|
|
41
|
+
|
|
42
|
+
function handler(ch) {
|
|
43
|
+
return function(cm) { return handleChar(cm, ch); };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getConfig(cm) {
|
|
47
|
+
var deflt = cm.state.closeBrackets;
|
|
48
|
+
if (!deflt) return null;
|
|
49
|
+
var mode = cm.getModeAt(cm.getCursor());
|
|
50
|
+
return mode.closeBrackets || deflt;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function handleBackspace(cm) {
|
|
54
|
+
var conf = getConfig(cm);
|
|
55
|
+
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
|
|
56
|
+
|
|
57
|
+
var pairs = getOption(conf, "pairs");
|
|
58
|
+
var ranges = cm.listSelections();
|
|
59
|
+
for (var i = 0; i < ranges.length; i++) {
|
|
60
|
+
if (!ranges[i].empty()) return CodeMirror.Pass;
|
|
61
|
+
var around = charsAround(cm, ranges[i].head);
|
|
62
|
+
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
|
63
|
+
}
|
|
64
|
+
for (var i = ranges.length - 1; i >= 0; i--) {
|
|
65
|
+
var cur = ranges[i].head;
|
|
66
|
+
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function handleEnter(cm) {
|
|
71
|
+
var conf = getConfig(cm);
|
|
72
|
+
var explode = conf && getOption(conf, "explode");
|
|
73
|
+
if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
|
|
74
|
+
|
|
75
|
+
var ranges = cm.listSelections();
|
|
76
|
+
for (var i = 0; i < ranges.length; i++) {
|
|
77
|
+
if (!ranges[i].empty()) return CodeMirror.Pass;
|
|
78
|
+
var around = charsAround(cm, ranges[i].head);
|
|
79
|
+
if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
|
80
|
+
}
|
|
81
|
+
cm.operation(function() {
|
|
82
|
+
cm.replaceSelection("\n\n", null);
|
|
83
|
+
cm.execCommand("goCharLeft");
|
|
84
|
+
ranges = cm.listSelections();
|
|
85
|
+
for (var i = 0; i < ranges.length; i++) {
|
|
86
|
+
var line = ranges[i].head.line;
|
|
87
|
+
cm.indentLine(line, null, true);
|
|
88
|
+
cm.indentLine(line + 1, null, true);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function contractSelection(sel) {
|
|
94
|
+
var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
|
|
95
|
+
return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
|
|
96
|
+
head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function handleChar(cm, ch) {
|
|
100
|
+
var conf = getConfig(cm);
|
|
101
|
+
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
|
|
102
|
+
|
|
103
|
+
var pairs = getOption(conf, "pairs");
|
|
104
|
+
var pos = pairs.indexOf(ch);
|
|
105
|
+
if (pos == -1) return CodeMirror.Pass;
|
|
106
|
+
var triples = getOption(conf, "triples");
|
|
107
|
+
|
|
108
|
+
var identical = pairs.charAt(pos + 1) == ch;
|
|
109
|
+
var ranges = cm.listSelections();
|
|
110
|
+
var opening = pos % 2 == 0;
|
|
111
|
+
|
|
112
|
+
var type;
|
|
113
|
+
for (var i = 0; i < ranges.length; i++) {
|
|
114
|
+
var range = ranges[i], cur = range.head, curType;
|
|
115
|
+
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
|
|
116
|
+
if (opening && !range.empty()) {
|
|
117
|
+
curType = "surround";
|
|
118
|
+
} else if ((identical || !opening) && next == ch) {
|
|
119
|
+
if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
|
|
120
|
+
curType = "skipThree";
|
|
121
|
+
else
|
|
122
|
+
curType = "skip";
|
|
123
|
+
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
|
|
124
|
+
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &&
|
|
125
|
+
(cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
|
|
126
|
+
curType = "addFour";
|
|
127
|
+
} else if (identical) {
|
|
128
|
+
if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both";
|
|
129
|
+
else return CodeMirror.Pass;
|
|
130
|
+
} else if (opening && (cm.getLine(cur.line).length == cur.ch ||
|
|
131
|
+
isClosingBracket(next, pairs) ||
|
|
132
|
+
/\s/.test(next))) {
|
|
133
|
+
curType = "both";
|
|
134
|
+
} else {
|
|
135
|
+
return CodeMirror.Pass;
|
|
136
|
+
}
|
|
137
|
+
if (!type) type = curType;
|
|
138
|
+
else if (type != curType) return CodeMirror.Pass;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
|
|
142
|
+
var right = pos % 2 ? ch : pairs.charAt(pos + 1);
|
|
143
|
+
cm.operation(function() {
|
|
144
|
+
if (type == "skip") {
|
|
145
|
+
cm.execCommand("goCharRight");
|
|
146
|
+
} else if (type == "skipThree") {
|
|
147
|
+
for (var i = 0; i < 3; i++)
|
|
148
|
+
cm.execCommand("goCharRight");
|
|
149
|
+
} else if (type == "surround") {
|
|
150
|
+
var sels = cm.getSelections();
|
|
151
|
+
for (var i = 0; i < sels.length; i++)
|
|
152
|
+
sels[i] = left + sels[i] + right;
|
|
153
|
+
cm.replaceSelections(sels, "around");
|
|
154
|
+
sels = cm.listSelections().slice();
|
|
155
|
+
for (var i = 0; i < sels.length; i++)
|
|
156
|
+
sels[i] = contractSelection(sels[i]);
|
|
157
|
+
cm.setSelections(sels);
|
|
158
|
+
} else if (type == "both") {
|
|
159
|
+
cm.replaceSelection(left + right, null);
|
|
160
|
+
cm.triggerElectric(left + right);
|
|
161
|
+
cm.execCommand("goCharLeft");
|
|
162
|
+
} else if (type == "addFour") {
|
|
163
|
+
cm.replaceSelection(left + left + left + left, "before");
|
|
164
|
+
cm.execCommand("goCharRight");
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function isClosingBracket(ch, pairs) {
|
|
170
|
+
var pos = pairs.lastIndexOf(ch);
|
|
171
|
+
return pos > -1 && pos % 2 == 1;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function charsAround(cm, pos) {
|
|
175
|
+
var str = cm.getRange(Pos(pos.line, pos.ch - 1),
|
|
176
|
+
Pos(pos.line, pos.ch + 1));
|
|
177
|
+
return str.length == 2 ? str : null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Project the token type that will exists after the given char is
|
|
181
|
+
// typed, and use it to determine whether it would cause the start
|
|
182
|
+
// of a string token.
|
|
183
|
+
function enteringString(cm, pos, ch) {
|
|
184
|
+
var line = cm.getLine(pos.line);
|
|
185
|
+
var token = cm.getTokenAt(pos);
|
|
186
|
+
if (/\bstring2?\b/.test(token.type)) return false;
|
|
187
|
+
var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
|
|
188
|
+
stream.pos = stream.start = token.start;
|
|
189
|
+
for (;;) {
|
|
190
|
+
var type1 = cm.getMode().token(stream, token.state);
|
|
191
|
+
if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1);
|
|
192
|
+
stream.start = stream.pos;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
2
|
+
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tag-closer extension for CodeMirror.
|
|
6
|
+
*
|
|
7
|
+
* This extension adds an "autoCloseTags" option that can be set to
|
|
8
|
+
* either true to get the default behavior, or an object to further
|
|
9
|
+
* configure its behavior.
|
|
10
|
+
*
|
|
11
|
+
* These are supported options:
|
|
12
|
+
*
|
|
13
|
+
* `whenClosing` (default true)
|
|
14
|
+
* Whether to autoclose when the '/' of a closing tag is typed.
|
|
15
|
+
* `whenOpening` (default true)
|
|
16
|
+
* Whether to autoclose the tag when the final '>' of an opening
|
|
17
|
+
* tag is typed.
|
|
18
|
+
* `dontCloseTags` (default is empty tags for HTML, none for XML)
|
|
19
|
+
* An array of tag names that should not be autoclosed.
|
|
20
|
+
* `indentTags` (default is block tags for HTML, none for XML)
|
|
21
|
+
* An array of tag names that should, when opened, cause a
|
|
22
|
+
* blank line to be added inside the tag, and the blank line and
|
|
23
|
+
* closing line to be indented.
|
|
24
|
+
*
|
|
25
|
+
* See demos/closetag.html for a usage example.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
(function(mod) {
|
|
29
|
+
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
30
|
+
mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
|
|
31
|
+
else if (typeof define == "function" && define.amd) // AMD
|
|
32
|
+
define(["../../lib/codemirror", "../fold/xml-fold"], mod);
|
|
33
|
+
else // Plain browser env
|
|
34
|
+
mod(CodeMirror);
|
|
35
|
+
})(function(CodeMirror) {
|
|
36
|
+
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
|
|
37
|
+
if (old != CodeMirror.Init && old)
|
|
38
|
+
cm.removeKeyMap("autoCloseTags");
|
|
39
|
+
if (!val) return;
|
|
40
|
+
var map = {name: "autoCloseTags"};
|
|
41
|
+
if (typeof val != "object" || val.whenClosing)
|
|
42
|
+
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
|
|
43
|
+
if (typeof val != "object" || val.whenOpening)
|
|
44
|
+
map["'>'"] = function(cm) { return autoCloseGT(cm); };
|
|
45
|
+
cm.addKeyMap(map);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
|
|
49
|
+
"source", "track", "wbr"];
|
|
50
|
+
var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
|
|
51
|
+
"h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
|
|
52
|
+
|
|
53
|
+
function autoCloseGT(cm) {
|
|
54
|
+
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
|
55
|
+
var ranges = cm.listSelections(), replacements = [];
|
|
56
|
+
for (var i = 0; i < ranges.length; i++) {
|
|
57
|
+
if (!ranges[i].empty()) return CodeMirror.Pass;
|
|
58
|
+
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
|
|
59
|
+
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
|
60
|
+
if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
|
|
61
|
+
|
|
62
|
+
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
|
|
63
|
+
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
|
|
64
|
+
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
|
|
65
|
+
|
|
66
|
+
var tagName = state.tagName;
|
|
67
|
+
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
|
|
68
|
+
var lowerTagName = tagName.toLowerCase();
|
|
69
|
+
// Don't process the '>' at the end of an end-tag or self-closing tag
|
|
70
|
+
if (!tagName ||
|
|
71
|
+
tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
|
|
72
|
+
tok.type == "tag" && state.type == "closeTag" ||
|
|
73
|
+
tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
|
|
74
|
+
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
|
|
75
|
+
closingTagExists(cm, tagName, pos, state, true))
|
|
76
|
+
return CodeMirror.Pass;
|
|
77
|
+
|
|
78
|
+
var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
|
|
79
|
+
replacements[i] = {indent: indent,
|
|
80
|
+
text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
|
|
81
|
+
newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (var i = ranges.length - 1; i >= 0; i--) {
|
|
85
|
+
var info = replacements[i];
|
|
86
|
+
cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
|
|
87
|
+
var sel = cm.listSelections().slice(0);
|
|
88
|
+
sel[i] = {head: info.newPos, anchor: info.newPos};
|
|
89
|
+
cm.setSelections(sel);
|
|
90
|
+
if (info.indent) {
|
|
91
|
+
cm.indentLine(info.newPos.line, null, true);
|
|
92
|
+
cm.indentLine(info.newPos.line + 1, null, true);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function autoCloseCurrent(cm, typingSlash) {
|
|
98
|
+
var ranges = cm.listSelections(), replacements = [];
|
|
99
|
+
var head = typingSlash ? "/" : "</";
|
|
100
|
+
for (var i = 0; i < ranges.length; i++) {
|
|
101
|
+
if (!ranges[i].empty()) return CodeMirror.Pass;
|
|
102
|
+
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
|
|
103
|
+
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
|
104
|
+
if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
|
|
105
|
+
tok.start != pos.ch - 1))
|
|
106
|
+
return CodeMirror.Pass;
|
|
107
|
+
// Kludge to get around the fact that we are not in XML mode
|
|
108
|
+
// when completing in JS/CSS snippet in htmlmixed mode. Does not
|
|
109
|
+
// work for other XML embedded languages (there is no general
|
|
110
|
+
// way to go from a mixed mode to its current XML state).
|
|
111
|
+
var replacement;
|
|
112
|
+
if (inner.mode.name != "xml") {
|
|
113
|
+
if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
|
|
114
|
+
replacement = head + "script";
|
|
115
|
+
else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
|
|
116
|
+
replacement = head + "style";
|
|
117
|
+
else
|
|
118
|
+
return CodeMirror.Pass;
|
|
119
|
+
} else {
|
|
120
|
+
if (!state.context || !state.context.tagName ||
|
|
121
|
+
closingTagExists(cm, state.context.tagName, pos, state))
|
|
122
|
+
return CodeMirror.Pass;
|
|
123
|
+
replacement = head + state.context.tagName;
|
|
124
|
+
}
|
|
125
|
+
if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
|
|
126
|
+
replacements[i] = replacement;
|
|
127
|
+
}
|
|
128
|
+
cm.replaceSelections(replacements);
|
|
129
|
+
ranges = cm.listSelections();
|
|
130
|
+
for (var i = 0; i < ranges.length; i++)
|
|
131
|
+
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
|
|
132
|
+
cm.indentLine(ranges[i].head.line);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function autoCloseSlash(cm) {
|
|
136
|
+
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
|
137
|
+
return autoCloseCurrent(cm, true);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
|
|
141
|
+
|
|
142
|
+
function indexOf(collection, elt) {
|
|
143
|
+
if (collection.indexOf) return collection.indexOf(elt);
|
|
144
|
+
for (var i = 0, e = collection.length; i < e; ++i)
|
|
145
|
+
if (collection[i] == elt) return i;
|
|
146
|
+
return -1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// If xml-fold is loaded, we use its functionality to try and verify
|
|
150
|
+
// whether a given tag is actually unclosed.
|
|
151
|
+
function closingTagExists(cm, tagName, pos, state, newTag) {
|
|
152
|
+
if (!CodeMirror.scanForClosingTag) return false;
|
|
153
|
+
var end = Math.min(cm.lastLine() + 1, pos.line + 500);
|
|
154
|
+
var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
|
|
155
|
+
if (!nextClose || nextClose.tag != tagName) return false;
|
|
156
|
+
var cx = state.context;
|
|
157
|
+
// If the immediate wrapping context contains onCx instances of
|
|
158
|
+
// the same tag, a closing tag only exists if there are at least
|
|
159
|
+
// that many closing tags of that type following.
|
|
160
|
+
for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
|
|
161
|
+
pos = nextClose.to;
|
|
162
|
+
for (var i = 1; i < onCx; i++) {
|
|
163
|
+
var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
|
|
164
|
+
if (!next || next.tag != tagName) return false;
|
|
165
|
+
pos = next.to;
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
});
|