comfy_middle_seat 4.0.0 → 4.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2261f0af74a7d60998b21a9f85feacdb454614e8f8bec638eb9f7a1aa3b2850
4
- data.tar.gz: 06244651d11d7868006fdb42cea0b0ac9119304af97b42cd563401cd4ee9fd52
3
+ metadata.gz: b5a4db65127e75cd26c7579614c4a0b7d9911cdc42c69642c23713a54f646c6e
4
+ data.tar.gz: c715bde4f3d50f585f996cb6279a07b317e6cbdcd67fa9cdb2ffcc981492bb62
5
5
  SHA512:
6
- metadata.gz: 4f52d95a635172aa91cff2536dc87167656c815e23c743cd648a1d2fccf1cccd875e1a1866081ebaa2837b6b3b17690f1e6b59f321a4aaaa915bdc81464374da
7
- data.tar.gz: 054772f74cc2c0a373bd7939b9a4f47da4f7bfbf71aab88db624da8c6df72614da456c0377d3fd327c9a5a9903f3afc6c823ef5ce0f62c2a642b5b40dc638d17
6
+ metadata.gz: e4a9cdd0915e2bc45dcb9f58d35711566972838f16569e6b64d9408c9265974d4609f916a0aa5911dc6a872b183003023b3372c6f8247100ede1528c3aec6ac8
7
+ data.tar.gz: fb6647ee01f1a0b907e314b379113100c3cc0062aa0baa91bbfa9f1b909539f1e8114719874e032d863b6c5e1f3ce36e98f6277bfd7ec7155fff2f3667089512
data/CHANGELOG.md CHANGED
@@ -12,12 +12,29 @@ This changelog follows the project's lineage: **Comfortable Mexican Sofa → Com
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [v4.0.1] - 2026-09-18
16
+
15
17
  ### Changed
16
18
 
17
- - Complete the implementation namespace and internal-path decoupling from Comfortable Media Surfer: current Ruby APIs now use `ComfyMiddleSeat`, library files live under `comfy_middle_seat`, and generated configuration belongs at `config/initializers/comfy_middle_seat.rb`.
18
- - Require applications upgrading from `comfortable_media_surfer` to rename the initializer and replace Ruby configuration or integration references from `ComfortableMediaSurfer` to `ComfyMiddleSeat`. The existing `comfy_cms_*` database tables, schema, and stored data remain unchanged, so no database migration is required.
19
- - Add the standalone `comfy-middle-seat-upgrade` executable to safely preview and convert a legacy initializer without booting Rails, preserving the original as a backup and refusing ambiguous or destructive changes.
20
- - Preserve Comfortable Media Surfer names and URLs where they describe project history, acknowledgements, inherited release notes, or upstream resources rather than the current API.
19
+ - Remove unsaved-changes navigation warnings. Local draft recovery remains available for Pages and Translations.
20
+
21
+ ## [v4.0.0] - 2026-09-18
22
+
23
+ ### Added
24
+
25
+ - Search pages by title, path, or content, and find files and images in the editor.
26
+ - Restore or discard locally saved drafts for Pages and Translations.
27
+ - Preview Page and Translation revisions before restoring them.
28
+ - Add `comfy-middle-seat-upgrade` to convert legacy initializers with a backup.
29
+
30
+ ### Changed
31
+
32
+ - Complete the rename from Comfortable Media Surfer to Comfy Middle Seat.
33
+ - Load page branches on demand and speed up page reordering.
34
+ - Preserve unsaved content when switching layouts; warn before discarding incompatible fields.
35
+ - Improve revision comparisons and prevent deletion of the root page.
36
+
37
+ **Upgrading:** Rename `config/initializers/comfortable_media_surfer.rb` to `comfy_middle_seat.rb` and replace `ComfortableMediaSurfer` Ruby references with `ComfyMiddleSeat`. Preview initializer conversion with `bundle exec comfy-middle-seat-upgrade --dry-run`. No database migration is required.
21
38
 
22
39
  ## [v3.2.1] - 2026-09-17
23
40
 
@@ -39,7 +56,7 @@ This changelog follows the project's lineage: **Comfortable Mexican Sofa → Com
39
56
  ### Changed
40
57
 
41
58
  - Publish the gem as `comfy_middle_seat` and rename the gemspec to `comfy_middle_seat.gemspec`.
42
- - At the time of v3.2.0, preserve the `ComfortableMediaSurfer` Ruby namespace and configuration while retaining the existing routes and database tables. The Unreleased namespace decoupling supersedes the Ruby compatibility behavior; the database compatibility remains unchanged.
59
+ - At the time of v3.2.0, preserve the `ComfortableMediaSurfer` Ruby namespace and configuration while retaining the existing routes and database tables. The v4.0.0 namespace rename supersedes the Ruby compatibility behavior; the database compatibility remains unchanged.
43
60
  - Move the version definition to `lib/comfy_middle_seat/version.rb` for release tooling, retaining a compatibility loader at the old path.
44
61
  - Run the main test suite in six isolated processes by default, with merged coverage and a separate `test:serial` task for Coveralls.
45
62
  - Update CI coverage to Rails 7.2, 8.0, and 8.1, with a separate browser/system test job.
@@ -57,7 +74,7 @@ This changelog follows the project's lineage: **Comfortable Mexican Sofa → Com
57
74
 
58
75
  ### Historical v3.2.0 upgrade behavior
59
76
 
60
- For v3.2.0, users replaced `comfortable_media_surfer` with `comfy_middle_seat` in the Gemfile while keeping the former Ruby namespace and initializer name. That release-specific compatibility guidance is preserved for history but is superseded by the Unreleased change: current upgrades must rename the initializer to `config/initializers/comfy_middle_seat.rb` and replace `ComfortableMediaSurfer` Ruby references with `ComfyMiddleSeat`. Neither stage changes the database schema.
77
+ For v3.2.0, users replaced `comfortable_media_surfer` with `comfy_middle_seat` in the Gemfile while keeping the former Ruby namespace and initializer name. That release-specific compatibility guidance is preserved for history but is superseded by v4.0.0: current upgrades must rename the initializer to `config/initializers/comfy_middle_seat.rb` and replace `ComfortableMediaSurfer` Ruby references with `ComfyMiddleSeat`. Neither stage changes the database schema.
61
78
 
62
79
  ## Comfortable Media Surfer — inherited releases
63
80
 
@@ -186,7 +203,9 @@ First release of `comfortable_media_surfer`. This new gem is a revival of [Comfo
186
203
 
187
204
  - Rebranded **ComfortableMexicanSofa** as **ComfortableMediaSurfer** in order to publish new gem (database table names and schema have not changed).
188
205
 
189
- [Unreleased]: https://github.com/avonderluft/comfy-middle-seat/compare/v3.2.1...master
206
+ [Unreleased]: https://github.com/avonderluft/comfy-middle-seat/compare/v4.0.1...master
207
+ [v4.0.1]: https://github.com/avonderluft/comfy-middle-seat/compare/v4.0.0...v4.0.1
208
+ [v4.0.0]: https://github.com/avonderluft/comfy-middle-seat/compare/v3.2.1...v4.0.0
190
209
  [v3.2.1]: https://github.com/avonderluft/comfy-middle-seat/compare/v3.2.0...v3.2.1
191
210
  [v3.2.0]: https://github.com/avonderluft/comfy-middle-seat/compare/eeb5d590f47b5d6bb70191fb81c781540753fa97...v3.2.0
192
211
  [v3.1.7]: https://github.com/shakacode/comfortable-media-surfer/compare/v3.1.6...v3.1.7
data/README.md CHANGED
@@ -2,69 +2,85 @@
2
2
 
3
3
  # Comfy Middle Seat
4
4
 
5
- It all depends on who is sitting on your left and on your right.
5
+ *A self-hosted, embeddable CMS engine for Rails 7.2+, 8.x*
6
6
 
7
- Comfy Middle Seat is a Rails CMS (Content Management System) engine, published as the `comfy_middle_seat` gem. It is descended from Comfortable Media Surfer and pays homage to the original Comfortable Mexican Sofa—with the same C.M.S. initials with a new place to sit.
7
+ Add editor-managed pages, reusable layouts, rich text, Markdown, files, translations, search, and revision history to an existing Rails application—without moving your content into a separate service.
8
8
 
9
- The current implementation uses the `ComfyMiddleSeat` Ruby namespace, `comfy_middle_seat` internal paths, and the initializer `config/initializers/comfy_middle_seat.rb`. Database storage remains compatible: the existing `comfy_cms_*` tables and schema are unchanged, so this namespace change requires no database migration.
9
+ Comfy Middle Seat is actively maintained and continues the lineage of Comfortable Mexican Sofa and Comfortable Media Surfer. It keeps the memorable C.M.S. initials, with a new place to sit. It all depend on who is sitting to your right and left.
10
10
 
11
- ## Project History
11
+ [Quick Start](#quick-start) · [Features](#features) · [Documentation](#documentation) · [Upgrading](#upgrading) · [Contributing](#contributing)
12
12
 
13
- - **[Comfortable Mexican Sofa](https://github.com/comfy/comfortable-mexican-sofa)**, created by Oleg Khabarov, is the original Rails CMS on which this project is built. Oleg deserves the lion's share of kudos.
14
- - **[oCcaMS](https://github.com/avonderluft/occams)** was an attempted revival of Sofa. Andrew vonderLuft was a contributor to [RadiantCMS](https://github.com/radiant/radiant) back in the day, but that project became inactive. He found Sofa and liked it even better than Radiant, but sadly it too became inactive. Hence Occams.
15
- - **[Comfortable Media Surfer](https://github.com/shakacode/comfortable-media-surfer)** revived Sofa under the sponsorship of ShakaCode, continuing its development for modern Rails applications.
16
- - **[Comfy Middle Seat](https://github.com/avonderluft/comfy-middle-seat)** began as a fork of Comfortable Media Surfer and is now implemented under its own `ComfyMiddleSeat` namespace and `comfy_middle_seat` paths.
13
+ ## Why Comfy Middle Seat?
17
14
 
18
- See the [CHANGELOG](CHANGELOG.md) for the inherited development history, and the original [Sofa releases](https://github.com/comfy/comfortable-mexican-sofa/releases) and [Surfer releases](https://github.com/shakacode/comfortable-media-surfer/releases) for earlier releases.
15
+ Choose Comfy Middle Seat when you want content editing inside your Rails application rather than a separate hosted CMS.
19
16
 
20
- ## Features
17
+ - Keep application code and CMS-rendered pages together.
18
+ - Own and host your content, database, and files.
19
+ - Use familiar Rails controllers, views, helpers, authentication, and authorization.
20
+ - Add CMS-managed pages without creating a separate frontend application.
21
+ - Extend or override the admin area using normal Rails conventions.
22
+
23
+ Comfy Middle Seat is best suited to Rails applications that render their own websites. It is not intended to be a hosted SaaS CMS or a JavaScript-first visual page builder.
21
24
 
22
- - Simple drop-in integration with Rails 7.2+ apps with minimal configuration
23
- * The CMS keeps clear from the rest of your application
24
- * Powerful page templating capability using [Content Tags](https://github.com/shakacode/comfortable-media-surfer/wiki/Docs:-Content-Tags)
25
- * [Multiple Sites](https://github.com/shakacode/comfortable-media-surfer/wiki/Sites) from a single installation
26
- * Multi-Language Support (i18n) (ca, cs, da, de, en, es, fi, fr, gr, hr, it, ja, nb, nl, pl, pt-BR, ru, sv, tr, uk, zh-CN, zh-TW) and page localization.
27
- * [CMS Seeds](https://github.com/shakacode/comfortable-media-surfer/wiki/CMS-Seeds) for initial content population
28
- * [Revision History](https://github.com/shakacode/comfortable-media-surfer/wiki/Revisions) to revert changes
29
- * [Extendable Admin Area](https://github.com/shakacode/comfortable-media-surfer/wiki/HowTo:-Reusing-Admin-Area) built with [Bootstrap 4](http://getbootstrap.com) (responsive design). Using [CodeMirror](http://codemirror.net) for HTML and Markdown highlighing and [Redactor](http://imperavi.com/redactor) as the WYSIWYG editor.
25
+ ## Features
30
26
 
31
- ## Dependencies
27
+ ### For content editors
32
28
 
33
- - File attachments are handled by [ActiveStorage](https://github.com/rails/rails/tree/master/activestorage). Make sure that you can run appropriate migrations by running: `rails active_storage:install`
34
- - Image resizing is done with with [ImageMagick](http://www.imagemagick.org/script/download.php), so make sure it's installed.
35
- - Pagination is handled by [kaminari](https://github.com/amatsuda/kaminari).
29
+ - Hierarchical pages with fast, on-demand tree navigation.
30
+ - Rich text, Markdown, plain text, images, files, dates, numbers, checkboxes, and reusable snippets.
31
+ - Search across page titles, paths, and content.
32
+ - Searchable image and file selection inside the editor.
33
+ - Local draft recovery for Pages and Translations.
34
+ - Revision history with comparison, preview, and restore workflows.
35
+ - Page translations and multilingual publishing.
36
+ - Multi-site publishing from one installation.
37
+ - Controls to publish or unpublish child pages together.
36
38
 
37
- ## Compatibility
39
+ ### For Rails developers
38
40
 
39
- On Ruby 3.2+, 4.x, Rails 7.2+, 8.x
41
+ - Drop-in Rails engine with configurable admin and public routes.
42
+ - Flexible layouts built with simple `{{ cms:... }}` content tags.
43
+ - Active Storage integration for files and images.
44
+ - CMS seed files for version-controlled starter content.
45
+ - Configurable authentication and authorization.
46
+ - Extendable admin views, controllers, helpers, and partials.
47
+ - Stable `comfy_cms_*` database tables for upgrades from Sofa and Surfer.
48
+ - CI coverage across current Ruby and Rails releases.
40
49
 
41
- ## Installation
50
+ ## Quick Start
42
51
 
43
- Add gem definition to your Gemfile:
52
+ Add the gem to your Rails application's `Gemfile`:
44
53
 
45
54
  ```ruby
46
- gem "comfy_middle_seat", "~> 3.2.0"
55
+ gem "comfy_middle_seat", "~> 4.0"
47
56
  ```
48
57
 
49
- Then, for a new installation, run these commands from the Rails project's root:
58
+ Install the gem and generate the CMS:
50
59
 
51
60
  ```sh
52
61
  bundle install
53
- rails generate comfy:cms
54
- rails db:migrate
55
- rails comfy:compile_assets
62
+ bin/rails active_storage:install
63
+ bin/rails generate comfy:cms
64
+ bin/rails db:migrate
65
+ bin/rails comfy:compile_assets
56
66
  ```
57
67
 
58
- `rails db:migrate` is part of a new installation. Applications upgrading from Comfortable Media Surfer already have the same tables and schema and do not need a database migration for the gem, namespace, or internal-path rename.
68
+ The generator adds the CMS routes and creates `config/initializers/comfy_middle_seat.rb`.
59
69
 
60
- Now take a look inside your `config/routes.rb` file. You'll see where routes attach for the admin area and content serving. Make sure that content serving route appears as a very last item or it will make all other routes to be inaccessible.
70
+ Make sure the public content route remains after your application's other routes so it does not capture them first:
61
71
 
62
72
  ```ruby
63
73
  comfy_route :cms_admin, path: "/admin"
64
74
  comfy_route :cms, path: "/"
65
75
  ```
66
76
 
67
- The generator creates `config/initializers/comfy_middle_seat.rb`. Use `ComfyMiddleSeat` for configuration and other library API references:
77
+ Start Rails and open [http://localhost:3000/admin](http://localhost:3000/admin). The generated development credentials are `user` and `pass`.
78
+
79
+ > **Security:** Replace the default admin credentials or configure application authentication before exposing the admin area to a network.
80
+
81
+ ### Basic configuration
82
+
83
+ Use the `ComfyMiddleSeat` namespace in `config/initializers/comfy_middle_seat.rb`:
68
84
 
69
85
  ```ruby
70
86
  ComfyMiddleSeat.configure do |config|
@@ -72,52 +88,87 @@ ComfyMiddleSeat.configure do |config|
72
88
  config.admin_base_controller = "ApplicationController"
73
89
  end
74
90
 
75
- ComfyMiddleSeat::AccessControl::AdminAuthentication.username = "user"
91
+ ComfyMiddleSeat::AccessControl::AdminAuthentication.username = "admin-user"
76
92
  ComfyMiddleSeat::AccessControl::AdminAuthentication.password = "change-me"
77
93
  ```
78
94
 
79
- ## Converting from Comfortable Media Surfer, Comfortable Mexican Sofa, or Occams
95
+ The initializer documents additional options for authentication, authorization, revisions, locales, seeds, helpers, partials, and application integration.
96
+
97
+ ## How content works
98
+
99
+ A Site defines a hostname, path, and language. Layouts define page structure and the fields editors can manage. For example:
100
+
101
+ ```html
102
+ <div id="page">
103
+ {{ cms:snippet header }}
104
+ <div id="main">
105
+ <div id="content">
106
+ {{ cms:breadcrumbs }}
107
+ {{ cms:siblings exclude: "search,comments" }}
108
+ <hr/>
109
+ {{ cms:markdown content }}
110
+ </div>
111
+ </div>
112
+ </div>
113
+ ```
114
+
115
+ When an editor creates a Page using this Layout, the admin automatically presents fields for `title` and `content`. Content tags can also provide Markdown, files, images, dates, numbers, checkboxes, snippets, partials, helpers, navigation, and other reusable content.
80
116
 
81
- ### From Surfer to Middle Seat
117
+ ## Compatibility and requirements
82
118
 
83
- 1. Replace `comfortable_media_surfer` in your Gemfile with `comfy_middle_seat` and run `bundle install`. Do not include both gems.
84
- 2. From the Rails application root, preview and run the standalone initializer upgrader. It does not boot Rails:
119
+ | Component | Support |
120
+ | --- | --- |
121
+ | Ruby | 3.2 or newer; CI tests 3.3, 3.4, and 4.0 |
122
+ | Rails | CI tests 7.2, 8.0, and 8.1 |
123
+ | Node.js | 18 or newer for asset compilation |
124
+ | File storage | Active Storage |
125
+ | Image processing | ImageMagick |
126
+
127
+ Pagination is provided by [Kaminari](https://github.com/amatsuda/kaminari). The admin uses Bootstrap, CodeMirror, and Redactor.
128
+
129
+ ## Documentation
130
+
131
+ The [Comfortable Media Surfer Wiki](https://github.com/shakacode/comfortable-media-surfer/wiki) remains a reference for inherited CMS features while first-party Comfy Middle Seat documentation is expanded.
132
+
133
+ Useful starting points:
134
+
135
+ - [Content Tags](https://github.com/shakacode/comfortable-media-surfer/wiki/Content-Tags)
136
+ - [Multiple Sites](https://github.com/shakacode/comfortable-media-surfer/wiki/Sites)
137
+ - [CMS Seeds](https://github.com/shakacode/comfortable-media-surfer/wiki/CMS-Seeds)
138
+ - [Revision History](https://github.com/shakacode/comfortable-media-surfer/wiki/Revisions)
139
+ - [Extending the Admin Area](https://github.com/shakacode/comfortable-media-surfer/wiki/HowTo:-Reusing-Admin-Area)
140
+ - [Changelog](CHANGELOG.md)
141
+
142
+ When adapting upstream examples, use the `comfy_middle_seat` gem, `config/initializers/comfy_middle_seat.rb`, and the `ComfyMiddleSeat` Ruby namespace.
143
+
144
+ ## Upgrading
145
+
146
+ ### From Comfortable Media Surfer
147
+
148
+ 1. Replace `comfortable_media_surfer` with `comfy_middle_seat` in the `Gemfile`. Do not include both gems.
149
+ 2. Run `bundle install`.
150
+ 3. Preview and run the standalone initializer converter from the Rails application root:
85
151
 
86
152
  ```sh
87
153
  bundle exec comfy-middle-seat-upgrade --dry-run
88
154
  bundle exec comfy-middle-seat-upgrade
89
155
  ```
90
156
 
91
- It renames `config/initializers/comfortable_media_surfer.rb` to `config/initializers/comfy_middle_seat.rb`, updates the project namespace references inside it, and preserves the original as `config/initializers/comfortable_media_surfer.rb.bak`. It refuses to overwrite an existing initializer or backup.
92
- 3. In any other application integrations, replace Ruby references to `ComfortableMediaSurfer` with `ComfyMiddleSeat`.
157
+ 4. Replace any remaining Ruby references from `ComfortableMediaSurfer` to `ComfyMiddleSeat`.
93
158
 
94
- For example:
159
+ The converter renames `config/initializers/comfortable_media_surfer.rb` to `config/initializers/comfy_middle_seat.rb`, updates namespace references, and preserves the original as a `.bak` file. It refuses to overwrite an existing initializer or backup.
95
160
 
96
- ```ruby
97
- # Before
98
- ComfortableMediaSurfer.configure do |config|
99
- config.cms_title = "My CMS"
100
- end
161
+ The existing `comfy_cms_*` tables, schema, and stored records are used as-is. No CMS database migration is required for this upgrade.
101
162
 
102
- # After
103
- ComfyMiddleSeat.configure do |config|
104
- config.cms_title = "My CMS"
105
- end
106
- ```
163
+ ### From Comfortable Mexican Sofa
107
164
 
108
- Review the converted initializer and remove its `.bak` file when satisfied. The database tables, schema, and stored records remain unchanged; existing `comfy_cms_*` tables are used as-is, and **no database migration is required** for this upgrade.
165
+ Upgrade the application to Rails 7.2 or newer, replace the old gem with `comfy_middle_seat`, run `bundle install`, generate or convert `config/initializers/comfy_middle_seat.rb`, and update application integrations to use `ComfyMiddleSeat`.
109
166
 
110
- ### From Sofa to Middle Seat
167
+ Sofa and Comfy Middle Seat use the same `comfy_cms_*` database table names, so the CMS tables do not need to be renamed.
111
168
 
112
- The database structure is the same, so no database migration is required for the CMS tables. Your Sofa project must first be upgraded to Rails 7.2 or newer. Then update the Gemfile, run `bundle install`, use `config/initializers/comfy_middle_seat.rb`, and update CMS library references in application code to `ComfyMiddleSeat`:
169
+ ### From Occams
113
170
 
114
- ```ruby
115
- gem "comfy_middle_seat", "~> 3.2.0"
116
- ```
117
-
118
- ### From Occams to Middle Seat
119
-
120
- The project must be on Rails 7.2 or newer. Unlike Surfer and Sofa, Occams used different table names, so converting an Occams database requires the following SQL. This is an Occams data conversion, not a migration caused by the current `ComfyMiddleSeat` namespace or internal-path change.
171
+ Upgrade the application to Rails 7.2 or newer and replace Occams with `comfy_middle_seat`. Occams used different table names and namespace values, so its data requires conversion:
121
172
 
122
173
  ```sql
123
174
  ALTER TABLE occams_cms_categories RENAME TO comfy_cms_categories;
@@ -141,55 +192,44 @@ UPDATE comfy_cms_revisions SET record_type = 'Comfy::Cms::Snippet' WHERE record_
141
192
  UPDATE active_storage_attachments SET record_type = 'Comfy::Cms::File' WHERE record_type = 'Occams::Cms::File';
142
193
  ```
143
194
 
144
- ## Quick Start Guide
145
-
146
- After finishing installation you should be able to navigate to http://localhost:3000/admin
195
+ Back up the database and test this conversion outside production first.
147
196
 
148
- The default username and password are `user` and `pass`. Change them before exposing the application. Admin credentials and other CMS settings are configured in `config/initializers/comfy_middle_seat.rb` through the `ComfyMiddleSeat` namespace.
197
+ ## Project history
149
198
 
150
- Before creating pages and populating them with content we need to create a Site. Site defines a hostname, content path and its language.
199
+ - [Comfortable Mexican Sofa](https://github.com/comfy/comfortable-mexican-sofa), created by Oleg Khabarov, established the original Rails CMS.
200
+ - [oCcaMS](https://github.com/avonderluft/occams) explored a revival after Sofa became inactive.
201
+ - [Comfortable Media Surfer](https://github.com/shakacode/comfortable-media-surfer), sponsored by ShakaCode, brought the project forward for current Rails versions.
202
+ - [Comfy Middle Seat](https://github.com/avonderluft/comfy-middle-seat) continues that work under its own namespace, release line, and maintenance direction.
151
203
 
152
- After creating a Site, you need to make a Layout. Layout is the template of your pages; it defines some reusable content (like header and footer, for example) and places where the content goes. A very simple layout can look like this:
153
-
154
- ```html
155
- <html>
156
- <body>
157
- <h1>{{ cms:text title }}</h1>
158
- {{ cms:wysiwyg content }}
159
- </body>
160
- </html>
161
- ```
162
-
163
- Once you have a layout, you may start creating pages and populating content. It's that easy.
164
-
165
- ## Documentation
166
-
167
- The [Comfortable Media Surfer Wiki](https://github.com/shakacode/comfortable-media-surfer/wiki) remains an upstream reference for inherited CMS features, including [Content Tags](https://github.com/shakacode/comfortable-media-surfer/wiki/Docs:-Content-Tags). These historical upstream links are intentionally preserved. When adapting its examples, use the `comfy_middle_seat` gem, `config/initializers/comfy_middle_seat.rb`, and the `ComfyMiddleSeat` Ruby namespace; upstream examples that use `ComfortableMediaSurfer` show the former API and must be updated.
204
+ See the [Changelog](CHANGELOG.md), [Sofa releases](https://github.com/comfy/comfortable-mexican-sofa/releases), and [Surfer releases](https://github.com/shakacode/comfortable-media-surfer/releases) for the complete inherited history.
168
205
 
169
206
  ## Add-ons
170
207
 
171
- If you want to add a Blog functionality to your app take a look at
172
- [ComfyBlog](https://github.com/comfy/comfy-blog).
173
-
174
- ![Admin Area Preview](doc/preview.jpg)
208
+ For blog functionality, see [ComfyBlog](https://github.com/comfy/comfy-blog).
175
209
 
210
+ ## Contributing
176
211
 
177
- #### Contributing
212
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and pull-request guidance.
178
213
 
179
- Comfy Middle Seat can run like any Rails application in development. It's as easy to work on as any other Rails app. For more detail, see [CONTRIBUTING](CONTRIBUTING.md).
214
+ The main checks are:
180
215
 
181
- #### Testing
216
+ ```sh
217
+ bundle exec rake test
218
+ bundle exec rails test:system
219
+ bundle exec rubocop
220
+ ```
182
221
 
183
- - `bin/rails db:migrate RAILS_ENV=test`
184
- - `rake db:test:prepare`
185
- - `rake test`
222
+ Bug reports and focused feature proposals can be opened through [GitHub Issues](https://github.com/avonderluft/comfy-middle-seat/issues).
186
223
 
187
- #### Acknowledgements
224
+ ## Acknowledgements
188
225
 
189
- - To [Oleg Khabarov](https://github.com/GBH) and the contributors to [Comfortable Mexican Sofa](https://github.com/comfy/comfortable-mexican-sofa), the original CMS.
190
- - To [ShakaCode](https://github.com/shakacode) and the contributors to [Comfortable Media Surfer](https://github.com/shakacode/comfortable-media-surfer), whose revival this fork builds on.
191
- - To [Roman Almeida](https://github.com/nasmorn) for contributing OEM License for [Redactor Text Editor](http://imperavi.com/redactor).
226
+ - [Oleg Khabarov](https://github.com/GBH) and the contributors to [Comfortable Mexican Sofa](https://github.com/comfy/comfortable-mexican-sofa), the original Comfy CMS.
227
+ - [Andrew vonderLuft](https://github.com/avonderluft) for reviving Sofa with the [oCcaMS](https://github.com/avonderluft/occams) project, and carrying it forward.
228
+ - [ShakaCode](https://github.com/shakacode) for sponsoring the revived project as [Comfortable Media Surfer](https://github.com/shakacode/comfortable-media-surfer).
229
+ - [Roman Almeida](https://github.com/nasmorn) for contributing the OEM license for [Redactor Text Editor](https://imperavi.com/redactor/).
192
230
 
193
231
  ---
194
232
 
195
- Copyright 2010-2019 Oleg Khabarov, 2024-2026 ShakaCode LLC, 2026 Andrew vonderLuft.<br/>Released under the [MIT license](LICENSE)
233
+ Copyright 2010-2019 Oleg Khabarov, 2024-2026 ShakaCode LLC, 2026 Andrew vonderLuft.
234
+
235
+ Released under the [MIT License](LICENSE).
@@ -15,7 +15,6 @@ import "./base";
15
15
  import "./categories";
16
16
  import "./codemirror";
17
17
  import "./diff";
18
- import "./dirty_forms";
19
18
  import "./draft_forms";
20
19
  import "./file_link";
21
20
  import "./file_upload";
@@ -32,13 +32,11 @@
32
32
  CMS.fileUpload.init();
33
33
  CMS.diff();
34
34
  CMS.draftForms.init();
35
- CMS.dirtyForms.init();
36
35
  };
37
36
 
38
37
  CMS.dispose = () => {
39
38
  CMS.pageFragments.dispose();
40
39
  CMS.draftForms.dispose();
41
- CMS.dirtyForms.dispose();
42
40
  CMS.codemirror.dispose();
43
41
  CMS.wysiwyg.dispose();
44
42
  CMS.files.dispose();
@@ -26,10 +26,6 @@ module Comfy
26
26
  def cms_draft_form_data(*key_parts, record:)
27
27
  namespace = session[:comfy_cms_draft_namespace] ||= SecureRandom.hex(16)
28
28
  {
29
- cms_unsaved_message: t(
30
- 'comfy.admin.cms.forms.unsaved_changes',
31
- default: 'You have unsaved changes. Are you sure you want to leave this page?'
32
- ),
33
29
  cms_draft_key: ['comfy-cms:draft:v1', namespace, *key_parts].join(':'),
34
30
  cms_draft_title: t('comfy.admin.cms.drafts.title', default: 'Unsaved draft found'),
35
31
  cms_draft_message: t(
@@ -26,6 +26,10 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.required_ruby_version = '>= 3.2.0'
28
28
  spec.metadata['rubygems_mfa_required'] = 'true'
29
+ spec.metadata['source_code_uri'] = spec.homepage
30
+ spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
31
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/master/CHANGELOG.md"
32
+ spec.metadata['documentation_uri'] = "#{spec.homepage}/blob/master/README.md#documentation"
29
33
 
30
34
  spec.add_dependency 'active_link_to', '~> 1.0', '>= 1.0.5'
31
35
  spec.add_dependency 'comfy_bootstrap_form', '~> 4.0', '>= 4.0.0'
@@ -64,8 +64,6 @@ ar:
64
64
  snippets: مقتطفات
65
65
  files: ملفات
66
66
 
67
- forms:
68
- unsaved_changes: لديك تغييرات غير محفوظة. هل أنت متأكد أنك تريد مغادرة هذه الصفحة؟
69
67
 
70
68
  search:
71
69
  submit: بحث
@@ -64,8 +64,6 @@ ca:
64
64
  snippets: Fragments
65
65
  files: Arxius
66
66
 
67
- forms:
68
- unsaved_changes: Teniu canvis sense desar. Esteu segur que voleu sortir d'aquesta pàgina?
69
67
 
70
68
  search:
71
69
  submit: Cerca
@@ -64,8 +64,6 @@ cs:
64
64
  snippets: Úryvky
65
65
  files: Soubory
66
66
 
67
- forms:
68
- unsaved_changes: Máte neuložené změny. Opravdu chcete tuto stránku opustit?
69
67
 
70
68
  search:
71
69
  submit: Hledat
@@ -64,8 +64,6 @@ da:
64
64
  snippets: Snippets
65
65
  files: Filer
66
66
 
67
- forms:
68
- unsaved_changes: Du har ændringer, der ikke er gemt. Er du sikker på, at du vil forlade denne side?
69
67
 
70
68
  search:
71
69
  submit: Søg
@@ -64,8 +64,6 @@ de:
64
64
  snippets: Schnipsel
65
65
  files: Dateien
66
66
 
67
- forms:
68
- unsaved_changes: Sie haben ungespeicherte Änderungen. Möchten Sie diese Seite wirklich verlassen?
69
67
 
70
68
  search:
71
69
  submit: Suchen
@@ -64,8 +64,6 @@ en:
64
64
  snippets: Snippets
65
65
  files: Files
66
66
 
67
- forms:
68
- unsaved_changes: You have unsaved changes. Are you sure you want to leave this page?
69
67
 
70
68
  search:
71
69
  submit: Search
@@ -64,8 +64,6 @@ es:
64
64
  snippets: Fragmentos
65
65
  files: Archivos
66
66
 
67
- forms:
68
- unsaved_changes: Tiene cambios sin guardar. ¿Está seguro de que desea salir de esta página?
69
67
 
70
68
  search:
71
69
  submit: Buscar
@@ -64,8 +64,6 @@ fi:
64
64
  snippets: Koodinpätkät
65
65
  files: Tiedostot
66
66
 
67
- forms:
68
- unsaved_changes: Sinulla on tallentamattomia muutoksia. Haluatko varmasti poistua tältä sivulta?
69
67
 
70
68
  search:
71
69
  submit: Hae
@@ -64,8 +64,6 @@ fr:
64
64
  snippets: Fragments
65
65
  files: Fichiers
66
66
 
67
- forms:
68
- unsaved_changes: Vous avez des modifications non enregistrées. Êtes-vous sûr de vouloir quitter cette page ?
69
67
 
70
68
  search:
71
69
  submit: Rechercher
@@ -64,8 +64,6 @@ gr:
64
64
  snippets: Snippets
65
65
  files: Αρχεία
66
66
 
67
- forms:
68
- unsaved_changes: Έχετε μη αποθηκευμένες αλλαγές. Είστε σίγουροι ότι θέλετε να φύγετε από αυτήν τη σελίδα;
69
67
 
70
68
  search:
71
69
  submit: Αναζήτηση
@@ -64,8 +64,6 @@ hr:
64
64
  snippets: Isječci
65
65
  files: Datoteke
66
66
 
67
- forms:
68
- unsaved_changes: Imate nespremljene promjene. Jeste li sigurni da želite napustiti ovu stranicu?
69
67
 
70
68
  search:
71
69
  submit: Pretraži
@@ -64,8 +64,6 @@ it:
64
64
  snippets: Snippet
65
65
  files: Files
66
66
 
67
- forms:
68
- unsaved_changes: Hai modifiche non salvate. Vuoi davvero lasciare questa pagina?
69
67
 
70
68
  search:
71
69
  submit: Cerca
@@ -64,8 +64,6 @@ ja:
64
64
  snippets: スニペット
65
65
  files: ファイル
66
66
 
67
- forms:
68
- unsaved_changes: 保存されていない変更があります。このページを離れてもよろしいですか?
69
67
 
70
68
  search:
71
69
  submit: 検索
@@ -64,8 +64,6 @@ nb:
64
64
  snippets: Snutter
65
65
  files: Filer
66
66
 
67
- forms:
68
- unsaved_changes: Du har ulagrede endringer. Er du sikker på at du vil forlate denne siden?
69
67
 
70
68
  search:
71
69
  submit: Søk
@@ -64,8 +64,6 @@ nl:
64
64
  snippets: Snippets
65
65
  files: Bestanden
66
66
 
67
- forms:
68
- unsaved_changes: U hebt niet-opgeslagen wijzigingen. Weet u zeker dat u deze pagina wilt verlaten?
69
67
 
70
68
  search:
71
69
  submit: Zoeken
@@ -64,8 +64,6 @@ pl:
64
64
  snippets: Snippety
65
65
  files: Pliki
66
66
 
67
- forms:
68
- unsaved_changes: Masz niezapisane zmiany. Czy na pewno chcesz opuścić tę stronę?
69
67
 
70
68
  search:
71
69
  submit: Szukaj
@@ -64,8 +64,6 @@ pt-BR:
64
64
  snippets: Fragmentos
65
65
  files: Arquivos
66
66
 
67
- forms:
68
- unsaved_changes: Você tem alterações não salvas. Tem certeza de que deseja sair desta página?
69
67
 
70
68
  search:
71
69
  submit: Pesquisar
@@ -64,8 +64,6 @@ ru:
64
64
  snippets: Сниппеты
65
65
  files: Файлы
66
66
 
67
- forms:
68
- unsaved_changes: У вас есть несохранённые изменения. Вы уверены, что хотите покинуть эту страницу?
69
67
 
70
68
  search:
71
69
  submit: Поиск
@@ -64,8 +64,6 @@ sk:
64
64
  snippets: Fragmenty
65
65
  files: Súbory
66
66
 
67
- forms:
68
- unsaved_changes: Máte neuložené zmeny. Naozaj chcete opustiť túto stránku?
69
67
 
70
68
  search:
71
69
  submit: Hľadať
@@ -64,8 +64,6 @@ sv:
64
64
  snippets: Snippets
65
65
  files: Filer
66
66
 
67
- forms:
68
- unsaved_changes: Du har osparade ändringar. Är du säker på att du vill lämna den här sidan?
69
67
 
70
68
  search:
71
69
  submit: Sök
@@ -64,8 +64,6 @@ tr:
64
64
  snippets: Pasajlar
65
65
  files: Dosyalar
66
66
 
67
- forms:
68
- unsaved_changes: Kaydedilmemiş değişiklikleriniz var. Bu sayfadan ayrılmak istediğinizden emin misiniz?
69
67
 
70
68
  search:
71
69
  submit: Ara
@@ -64,8 +64,6 @@ uk:
64
64
  snippets: Сніппети
65
65
  files: Файли
66
66
 
67
- forms:
68
- unsaved_changes: У вас є незбережені зміни. Ви впевнені, що хочете залишити цю сторінку?
69
67
 
70
68
  search:
71
69
  submit: Пошук
@@ -64,8 +64,6 @@ zh-CN:
64
64
  snippets: 片段
65
65
  files: 文件
66
66
 
67
- forms:
68
- unsaved_changes: 您有未保存的更改。确定要离开此页面吗?
69
67
 
70
68
  search:
71
69
  submit: 搜索
@@ -64,8 +64,6 @@ zh-TW:
64
64
  snippets: 片段
65
65
  files: 文件
66
66
 
67
- forms:
68
- unsaved_changes: 您有尚未儲存的變更。確定要離開此頁面嗎?
69
67
 
70
68
  search:
71
69
  submit: 搜尋
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ComfyMiddleSeat
4
- VERSION = '4.0.0'
4
+ VERSION = '4.0.2'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: comfy_middle_seat
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleg Khabarov
@@ -233,7 +233,6 @@ files:
233
233
  - app/assets/javascripts/comfy/admin/cms/codemirror.js
234
234
  - app/assets/javascripts/comfy/admin/cms/custom.js
235
235
  - app/assets/javascripts/comfy/admin/cms/diff.js
236
- - app/assets/javascripts/comfy/admin/cms/dirty_forms.js
237
236
  - app/assets/javascripts/comfy/admin/cms/draft_forms.js
238
237
  - app/assets/javascripts/comfy/admin/cms/file_link.js
239
238
  - app/assets/javascripts/comfy/admin/cms/file_upload.js
@@ -648,6 +647,10 @@ licenses:
648
647
  - MIT
649
648
  metadata:
650
649
  rubygems_mfa_required: 'true'
650
+ source_code_uri: https://github.com/avonderluft/comfy-middle-seat
651
+ bug_tracker_uri: https://github.com/avonderluft/comfy-middle-seat/issues
652
+ changelog_uri: https://github.com/avonderluft/comfy-middle-seat/blob/master/CHANGELOG.md
653
+ documentation_uri: https://github.com/avonderluft/comfy-middle-seat/blob/master/README.md#documentation
651
654
  post_install_message: |
652
655
  Please run rake comfy:compile_assets to compile assets.
653
656
  Upgrading from comfortable_media_surfer? Run bundle exec comfy-middle-seat-upgrade --dry-run first.
@@ -1,201 +0,0 @@
1
- (() => {
2
- const defaultMessage =
3
- "You have unsaved changes. Are you sure you want to leave this page?";
4
-
5
- let forms = [];
6
- let baselines = new WeakMap();
7
- let submittingForms = new WeakSet();
8
- let navigationAllowed = false;
9
-
10
- const controlState = (control) => {
11
- if (!control.name) return null;
12
-
13
- const type = (control.type || "").toLowerCase();
14
- if (["button", "image", "reset", "submit"].includes(type)) return null;
15
-
16
- if (type === "checkbox" || type === "radio") {
17
- return [control.name, type, control.value, control.checked];
18
- }
19
-
20
- if (type === "file") {
21
- return [
22
- control.name,
23
- type,
24
- Array.from(control.files).map((file) => [
25
- file.name,
26
- file.size,
27
- file.lastModified,
28
- ]),
29
- ];
30
- }
31
-
32
- if (control instanceof HTMLSelectElement && control.multiple) {
33
- return [
34
- control.name,
35
- type,
36
- Array.from(control.selectedOptions).map((option) => option.value),
37
- ];
38
- }
39
-
40
- return [control.name, type, control.value];
41
- };
42
-
43
- const formState = (form) =>
44
- JSON.stringify(Array.from(form.elements).map(controlState).filter(Boolean));
45
-
46
- const syncEditors = () => {
47
- if (CMS.codemirror && CMS.codemirror.sync) CMS.codemirror.sync();
48
- if (CMS.wysiwyg && CMS.wysiwyg.sync) CMS.wysiwyg.sync();
49
- };
50
-
51
- const dirtyForms = () => {
52
- syncEditors();
53
- return forms.filter(
54
- (form) =>
55
- form.isConnected &&
56
- baselines.has(form) &&
57
- baselines.get(form) !== formState(form)
58
- );
59
- };
60
-
61
- const formsRequiringWarning = () =>
62
- dirtyForms().filter((form) => !submittingForms.has(form));
63
-
64
- const warningMessage = (dirtyForm) =>
65
- dirtyForm.dataset.cmsUnsavedMessage || defaultMessage;
66
-
67
- const beforeUnload = (event) => {
68
- if (navigationAllowed || formsRequiringWarning().length === 0) return;
69
-
70
- event.preventDefault();
71
- event.returnValue = "";
72
- };
73
-
74
- const navigationTarget = (event) => {
75
- if (
76
- event.defaultPrevented ||
77
- event.button !== 0 ||
78
- event.metaKey ||
79
- event.ctrlKey ||
80
- event.shiftKey ||
81
- event.altKey
82
- ) {
83
- return null;
84
- }
85
-
86
- const link = event.target.closest("a[href]");
87
- if (!link || link.hasAttribute("download")) return null;
88
-
89
- const target = link.getAttribute("target");
90
- if (target && !["_self", "_top", "_parent", window.name].includes(target)) {
91
- return null;
92
- }
93
-
94
- const url = new URL(link.href, document.location.href);
95
- if (
96
- url.origin === document.location.origin &&
97
- url.pathname === document.location.pathname &&
98
- url.search === document.location.search &&
99
- url.hash
100
- ) {
101
- return null;
102
- }
103
-
104
- return link;
105
- };
106
-
107
- const allowCurrentNavigation = () => {
108
- navigationAllowed = true;
109
- window.setTimeout(() => {
110
- navigationAllowed = false;
111
- }, 0);
112
- };
113
-
114
- const confirmLinkNavigation = (event) => {
115
- if (navigationAllowed || !navigationTarget(event)) return;
116
-
117
- const dirtyForm = formsRequiringWarning()[0];
118
- if (!dirtyForm) return;
119
-
120
- if (!window.confirm(warningMessage(dirtyForm))) {
121
- event.preventDefault();
122
- event.stopImmediatePropagation();
123
- return;
124
- }
125
-
126
- allowCurrentNavigation();
127
- };
128
-
129
- const confirmTurbolinksNavigation = (event) => {
130
- if (navigationAllowed) return;
131
-
132
- const dirtyForm = formsRequiringWarning()[0];
133
- if (!dirtyForm) return;
134
-
135
- if (!window.confirm(warningMessage(dirtyForm))) {
136
- event.preventDefault();
137
- return;
138
- }
139
-
140
- allowCurrentNavigation();
141
- };
142
-
143
- const markSubmitting = (event) => {
144
- const form = event.target;
145
- const submitterTarget = event.submitter && event.submitter.formTarget;
146
- const target = submitterTarget || form.target;
147
-
148
- if (
149
- target &&
150
- !["_self", "_top", "_parent", window.name].includes(target)
151
- ) {
152
- return;
153
- }
154
-
155
- submittingForms.add(form);
156
- };
157
-
158
- window.CMS.dirtyForms = {
159
- init() {
160
- forms = Array.from(
161
- document.querySelectorAll("form[data-cms-unsaved-message]")
162
- );
163
- baselines = new WeakMap();
164
- submittingForms = new WeakSet();
165
- navigationAllowed = false;
166
-
167
- for (const form of forms) {
168
- const baseline =
169
- form.dataset.cmsSaveFailed === "true" ? null : formState(form);
170
- baselines.set(form, baseline);
171
- }
172
-
173
- window.addEventListener("beforeunload", beforeUnload);
174
- document.addEventListener("click", confirmLinkNavigation, true);
175
- document.addEventListener("submit", markSubmitting, true);
176
- document.addEventListener(
177
- "turbolinks:before-visit",
178
- confirmTurbolinksNavigation
179
- );
180
- },
181
-
182
- dispose() {
183
- window.removeEventListener("beforeunload", beforeUnload);
184
- document.removeEventListener("click", confirmLinkNavigation, true);
185
- document.removeEventListener("submit", markSubmitting, true);
186
- document.removeEventListener(
187
- "turbolinks:before-visit",
188
- confirmTurbolinksNavigation
189
- );
190
-
191
- forms = [];
192
- baselines = new WeakMap();
193
- submittingForms = new WeakSet();
194
- navigationAllowed = false;
195
- },
196
-
197
- isDirty() {
198
- return dirtyForms().length > 0;
199
- },
200
- };
201
- })();