phlexible 3.1.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/agents/rubocop-reviewer.md +31 -0
- data/.claude/hooks/protect-files.sh +11 -0
- data/.claude/hooks/rubocop-check.sh +18 -0
- data/.claude/settings.json +27 -0
- data/.claude/skills/test/SKILL.md +21 -0
- data/.rubocop.yml +1 -0
- data/CLAUDE.md +80 -0
- data/README.md +249 -126
- data/gemfiles/phlex1_rails7.gemfile.lock +2 -2
- data/gemfiles/phlex1_rails8.gemfile.lock +2 -2
- data/gemfiles/phlex2_rails7.gemfile.lock +2 -2
- data/gemfiles/phlex2_rails8.gemfile.lock +2 -2
- data/lib/phlexible/callbacks.rb +12 -0
- data/lib/phlexible/rails/a_element.rb +39 -3
- data/lib/phlexible/rails/auto_layout.rb +91 -0
- data/lib/phlexible/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4752fe1e276560bb8cca4c2115aabb11c36958588672cc5ec36d20bd3599d82e
|
|
4
|
+
data.tar.gz: 854eba7f90f061528db3de98a120bc457a679421103ef84eced0373457b1e3f1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ce11414a8a6a792e6a50b20ded0135037dc946267ee802f4ae9f9bb031b22a3689b5eadf821029ad4d29f1ce4599e6d9ffa96ac1b3c4d15285df7f1c37415f9
|
|
7
|
+
data.tar.gz: 3a825528fc039dffedbbe35a588c52bd9e3c5cdbd336e0e23793d316d1949cbad2dd090a69fb36fe911b57f2b69e46983d17c3022c10177aebc8704975c49f3a
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
You are a RuboCop style reviewer for the Phlexible Ruby gem.
|
|
2
|
+
|
|
3
|
+
## Project Style Rules
|
|
4
|
+
|
|
5
|
+
This project enforces strict RuboCop rules. Review changed Ruby files and flag violations.
|
|
6
|
+
|
|
7
|
+
### Disabled Syntax (hard errors)
|
|
8
|
+
- **No `unless`** — use `if !` or negated conditions instead
|
|
9
|
+
- **No `and` / `or` / `not`** — use `&&` / `||` / `!` instead
|
|
10
|
+
- **No numbered parameters** (`_1`, `_2`) — use named block parameters
|
|
11
|
+
|
|
12
|
+
### Formatting
|
|
13
|
+
- **Max line length**: 100 characters
|
|
14
|
+
- **Private method indentation**: `indented_internal_methods` — private/protected methods are indented one extra level beneath the access modifier
|
|
15
|
+
- **String literals**: prefer double quotes
|
|
16
|
+
|
|
17
|
+
### Enabled Plugins
|
|
18
|
+
Review against these RuboCop plugins:
|
|
19
|
+
- `rubocop-rails`
|
|
20
|
+
- `rubocop-minitest`
|
|
21
|
+
- `rubocop-performance`
|
|
22
|
+
- `rubocop-packaging`
|
|
23
|
+
- `rubocop-rake`
|
|
24
|
+
|
|
25
|
+
## Instructions
|
|
26
|
+
|
|
27
|
+
1. Read the files that were changed (use `jj diff --name-only` or check recent edits).
|
|
28
|
+
2. For each `.rb` file, check for violations of the rules above.
|
|
29
|
+
3. Run `bundle exec rubocop -P --fail-level C --force-exclusion <file>` to confirm.
|
|
30
|
+
4. Report any issues found, grouped by file, with the specific rule violated and a suggested fix.
|
|
31
|
+
5. If no issues are found, confirm the code passes review.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
INPUT=$(cat)
|
|
3
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')
|
|
4
|
+
|
|
5
|
+
# Block edits to lock files and generated gemfiles
|
|
6
|
+
if [[ "$FILE_PATH" == *.lock ]] || [[ "$FILE_PATH" == */gemfiles/*.gemfile ]]; then
|
|
7
|
+
echo "Do not edit lock files or generated Appraisal gemfiles directly." >&2
|
|
8
|
+
exit 2
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
exit 0
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
INPUT=$(cat)
|
|
3
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')
|
|
4
|
+
|
|
5
|
+
# Only lint Ruby files
|
|
6
|
+
if [[ "$FILE_PATH" != *.rb ]]; then
|
|
7
|
+
exit 0
|
|
8
|
+
fi
|
|
9
|
+
|
|
10
|
+
RESULT=$(bundle exec rubocop -P --fail-level C --force-exclusion "$FILE_PATH" 2>&1)
|
|
11
|
+
EXIT_CODE=$?
|
|
12
|
+
|
|
13
|
+
if [ $EXIT_CODE -ne 0 ]; then
|
|
14
|
+
echo "$RESULT" >&2
|
|
15
|
+
exit 2
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
exit 0
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Edit|Write",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"PostToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "Edit|Write",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/rubocop-check.sh",
|
|
21
|
+
"timeout": 30
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test
|
|
3
|
+
description: Run tests for the Phlexible gem across the Appraisal matrix
|
|
4
|
+
arguments:
|
|
5
|
+
- name: appraisal
|
|
6
|
+
description: "Appraisal to test: phlex1-rails7, phlex1-rails8, phlex2-rails7, phlex2-rails8, or 'all' (default: phlex2-rails8)"
|
|
7
|
+
default: "phlex2-rails8"
|
|
8
|
+
- name: file
|
|
9
|
+
description: "Optional test file path, or path:line for a single test"
|
|
10
|
+
disable-model-invocation: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Run Phlexible tests using the Appraisal gem for multi-version testing.
|
|
14
|
+
|
|
15
|
+
## Instructions
|
|
16
|
+
|
|
17
|
+
1. If `appraisal` is "all", run: `bundle exec appraisal rails test {file}`
|
|
18
|
+
2. Otherwise, run: `bundle exec appraisal {appraisal} rails test {file}`
|
|
19
|
+
3. If no `file` is given, omit it to run the full suite for that appraisal.
|
|
20
|
+
4. Report pass/fail/skip counts from the test output.
|
|
21
|
+
5. If tests fail, summarise which tests failed and why.
|
data/.rubocop.yml
CHANGED
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Phlexible is a Ruby gem providing helpers and extensions for [Phlex](https://phlex.fun) views in Rails applications. It supports Phlex 1.x and 2.x across Rails 7.2+ and Ruby >= 3.3.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
### Tests
|
|
12
|
+
|
|
13
|
+
Tests use Minitest (with maxitest, minitest-focus, minitest-spec-rails). The project uses [Appraisal](https://github.com/thoughtbot/appraisal) to test across multiple Phlex/Rails version combinations defined in `Appraisals`.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Run all tests across all appraisals (phlex1/rails7, phlex1/rails8, phlex2/rails7, phlex2/rails8)
|
|
17
|
+
bundle exec appraisal rails test
|
|
18
|
+
|
|
19
|
+
# Run tests for a specific appraisal
|
|
20
|
+
bundle exec appraisal phlex2/rails8 rails test
|
|
21
|
+
|
|
22
|
+
# Run a single test file
|
|
23
|
+
bundle exec appraisal phlex2/rails8 rails test test/phlexible/alias_view_test.rb
|
|
24
|
+
|
|
25
|
+
# Run a single test by line number
|
|
26
|
+
bundle exec appraisal phlex2/rails8 rails test test/phlexible/alias_view_test.rb:10
|
|
27
|
+
|
|
28
|
+
# Focus a single test (add `focus` before the test method, provided by minitest-focus)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Lint
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bundle exec rubocop -P --fail-level C
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Setup
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bin/setup
|
|
41
|
+
bundle exec appraisal install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Architecture
|
|
45
|
+
|
|
46
|
+
All source code lives under `lib/phlexible/`. Autoloading is handled by Zeitwerk (`Zeitwerk::Loader.for_gem` in `lib/phlexible.rb`).
|
|
47
|
+
|
|
48
|
+
### Module Organization
|
|
49
|
+
|
|
50
|
+
Modules are split into two categories:
|
|
51
|
+
|
|
52
|
+
**Standalone modules** (no Rails dependency):
|
|
53
|
+
- `Phlexible::AliasView` — `extend` in a view to create shortcut methods for rendering other components
|
|
54
|
+
- `Phlexible::Callbacks` — `include` for ActiveSupport::Callbacks-based `before_template`/`after_template`/`around_template` hooks. Also provides `before_layout`/`after_layout`/`around_layout` when used with `AutoLayout`.
|
|
55
|
+
- `Phlexible::PageTitle` — `include` for hierarchical page title management across nested views
|
|
56
|
+
- `Phlexible::ProcessAttributes` — `extend` to intercept and modify HTML element attributes before rendering (Phlex 2.x only; Phlex 1.x has this built-in). Prepends wrappers onto all StandardElements, VoidElements, and custom `register_element` methods.
|
|
57
|
+
|
|
58
|
+
**Rails-specific modules** (`lib/phlexible/rails/`):
|
|
59
|
+
- `ActionController::ImplicitRender` — convention-based automatic Phlex view rendering (resolves `UsersController#index` to `Users::IndexView`)
|
|
60
|
+
- `ControllerVariables` — explicit interface to expose controller instance variables to Phlex views via `controller_variable` class method
|
|
61
|
+
- `AElement` — overrides `a` tag to pass `href` through Rails `url_for`
|
|
62
|
+
- `ButtonTo` — Phlex component replacing Rails `button_to` helper
|
|
63
|
+
- `Responder` — integration with the [Responders](https://github.com/heartcombo/responders) gem
|
|
64
|
+
- `AutoLayout` — automatic layout wrapping based on view namespace conventions (e.g., `Views::Admin::Index` resolves to `Views::Layouts::Admin`). Includes `ViewAssigns` and `Callbacks`. Layout resolution is cached per class in production.
|
|
65
|
+
- `MetaTags` / `MetaTagsComponent` — define meta tags in controllers, render in views
|
|
66
|
+
|
|
67
|
+
### Key Patterns
|
|
68
|
+
|
|
69
|
+
- Modules use `extend` (AliasView, ProcessAttributes) or `include` (Callbacks, PageTitle, ControllerVariables) depending on whether they add class-level or instance-level behavior.
|
|
70
|
+
- `ProcessAttributes` uses `class_eval` with string interpolation to dynamically wrap every HTML element method — be careful when modifying this.
|
|
71
|
+
- `ControllerVariables` depends on both `ViewAssigns` and `Callbacks` internally.
|
|
72
|
+
- `AutoLayout` depends on both `ViewAssigns` and `Callbacks`. Layout resolution is cached in production via `resolved_layout` class method; use `reset_resolved_layout!` to clear.
|
|
73
|
+
- Tests use a Rails dummy app at `test/dummy/` for integration testing with real controllers/routes.
|
|
74
|
+
|
|
75
|
+
## Style
|
|
76
|
+
|
|
77
|
+
- RuboCop enforced with `rubocop-rails`, `rubocop-minitest`, `rubocop-performance`, `rubocop-packaging`, `rubocop-rake`.
|
|
78
|
+
- `unless`, `and`/`or`/`not`, and numbered parameters are **disabled** via `rubocop-disable_syntax`.
|
|
79
|
+
- `indented_internal_methods` indentation style (private methods indented one extra level).
|
|
80
|
+
- Max line length: 100 characters.
|
data/README.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
A bunch of helpers and goodies intended to make life with [Phlex](https://phlex.fun) even easier!
|
|
4
4
|
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Usage](#usage)
|
|
9
|
+
- [AliasView](#aliasview)
|
|
10
|
+
- [Callbacks](#callbacks)
|
|
11
|
+
- [PageTitle](#pagetitle)
|
|
12
|
+
- [ProcessAttributes](#processattributes)
|
|
13
|
+
- [Rails::ActionController::ImplicitRender](#railsactioncontrollerimplicitrender)
|
|
14
|
+
- [Rails::ControllerVariables](#railscontrollervariables)
|
|
15
|
+
- [Rails::AutoLayout](#railsautolayout)
|
|
16
|
+
- [Rails::AElement](#railsaelement)
|
|
17
|
+
- [Rails::ButtonTo](#railsbuttonto)
|
|
18
|
+
- [Rails::MetaTags](#railsmetatags)
|
|
19
|
+
- [Rails::Responder](#railsresponder)
|
|
20
|
+
- [Development](#development)
|
|
21
|
+
- [Contributing](#contributing)
|
|
22
|
+
- [License](#license)
|
|
23
|
+
- [Code of Conduct](#code-of-conduct)
|
|
24
|
+
|
|
5
25
|
## Installation
|
|
6
26
|
|
|
7
27
|
Install the gem and add to the application's Gemfile by executing:
|
|
@@ -14,49 +34,39 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
|
14
34
|
|
|
15
35
|
## Usage
|
|
16
36
|
|
|
17
|
-
###
|
|
37
|
+
### `AliasView`
|
|
18
38
|
|
|
19
|
-
|
|
39
|
+
Create an alias at a given `element`, to the given view class.
|
|
20
40
|
|
|
21
|
-
|
|
41
|
+
So instead of:
|
|
22
42
|
|
|
23
43
|
```ruby
|
|
24
|
-
class
|
|
25
|
-
def
|
|
26
|
-
|
|
44
|
+
class MyView < Phlex::HTML
|
|
45
|
+
def view_template
|
|
46
|
+
div do
|
|
47
|
+
render My::Awesome::Component.new
|
|
48
|
+
end
|
|
27
49
|
end
|
|
28
50
|
end
|
|
29
51
|
```
|
|
30
52
|
|
|
31
|
-
You can do
|
|
32
|
-
|
|
33
|
-
```ruby
|
|
34
|
-
class UsersController
|
|
35
|
-
include Phlexible::Rails::ActionController::ImplicitRender
|
|
36
|
-
end
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
##### View Resolution
|
|
40
|
-
|
|
41
|
-
By default, views are resolved using the `phlex_view_path` method, which constructs a path based on the controller and action name. For example, `UsersController#index` will look for `Users::IndexView`.
|
|
42
|
-
|
|
43
|
-
You can customize this behavior by overriding `phlex_view_path` in your controller:
|
|
53
|
+
You can instead do:
|
|
44
54
|
|
|
45
55
|
```ruby
|
|
46
|
-
class
|
|
47
|
-
|
|
56
|
+
class MyView < Phlex::HTML
|
|
57
|
+
extend Phlexible::AliasView
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
alias_view :awesome, -> { My::Awesome::Component }
|
|
50
60
|
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
def view_template
|
|
62
|
+
div do
|
|
63
|
+
awesome
|
|
53
64
|
end
|
|
65
|
+
end
|
|
54
66
|
end
|
|
55
67
|
```
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
#### `Callbacks`
|
|
69
|
+
### `Callbacks`
|
|
60
70
|
|
|
61
71
|
While Phlex does have `before_template`, `after_template`, and `around_template` hooks, they must be defined as regular Ruby methods, meaning you have to always remember to call `super` when redefining any hook method.
|
|
62
72
|
|
|
@@ -82,9 +92,115 @@ end
|
|
|
82
92
|
|
|
83
93
|
You can still use the regular `before_template`, `after_template`, and `around_template` hooks as well, but I recommend that if you include this module, that you use callbacks instead.
|
|
84
94
|
|
|
85
|
-
|
|
95
|
+
When used with `Rails::AutoLayout`, layout callbacks (`before_layout`, `after_layout`, `around_layout`) are also available. See the `Rails::AutoLayout` section below.
|
|
96
|
+
|
|
97
|
+
### `PageTitle`
|
|
98
|
+
|
|
99
|
+
Helper to assist in defining page titles within Phlex views. Also includes support for nested views, where each desendent view class will have its title prepended to the page title. Simply include *Phlexible::PageTitle* module and assign the title to the `page_title` class variable:
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
class MyView
|
|
103
|
+
include Phlexible::PageTitle
|
|
104
|
+
self.page_title = 'My Title'
|
|
105
|
+
end
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Then call the `page_title` method in the `<head>` of your page.
|
|
109
|
+
|
|
110
|
+
### `ProcessAttributes`
|
|
111
|
+
|
|
112
|
+
> This functionality is already built in to **Phlex >= 1**. This module is only needed for **Phlex >= 2**.
|
|
113
|
+
|
|
114
|
+
Allows you to intercept and modify HTML element attributes before they are rendered. This is useful for adding default attributes, transforming values, or conditionally modifying attributes based on other attributes.
|
|
115
|
+
|
|
116
|
+
Extend your view class with `Phlexible::ProcessAttributes` and define a `process_attributes` instance method that receives the attributes hash and returns the modified hash.
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
class MyView < Phlex::HTML
|
|
120
|
+
extend Phlexible::ProcessAttributes
|
|
121
|
+
|
|
122
|
+
def process_attributes(attrs)
|
|
123
|
+
# Add a default class to all elements
|
|
124
|
+
attrs[:class] ||= 'my-default-class'
|
|
125
|
+
attrs
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def view_template
|
|
129
|
+
div(id: 'container') { 'Hello' }
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This will output:
|
|
135
|
+
|
|
136
|
+
```html
|
|
137
|
+
<div id="container" class="my-default-class">Hello</div>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The `process_attributes` method is called for all standard HTML elements and void elements, as well as any custom elements registered with `register_element`.
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
class MyView < Phlex::HTML
|
|
144
|
+
extend Phlexible::ProcessAttributes
|
|
145
|
+
|
|
146
|
+
register_element :my_custom_element
|
|
147
|
+
|
|
148
|
+
def process_attributes(attrs)
|
|
149
|
+
attrs[:data_processed] = true
|
|
150
|
+
attrs
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def view_template
|
|
154
|
+
my_custom_element(name: 'test') { 'Custom content' }
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `Rails::ActionController::ImplicitRender`
|
|
160
|
+
|
|
161
|
+
Adds support for default and `action_missing` rendering of Phlex views. So instead of this:
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
class UsersController
|
|
165
|
+
def index
|
|
166
|
+
render Views::Users::Index.new
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def show
|
|
170
|
+
render Views::Users::Show.new
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
You can do this:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
class UsersController
|
|
179
|
+
include Phlexible::Rails::ActionController::ImplicitRender
|
|
180
|
+
end
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### View Resolution
|
|
184
|
+
|
|
185
|
+
By default, views are resolved using the `phlex_view_path` method, which constructs a path based on the controller and action name. For example, `UsersController#index` will look for `Views::Users::IndexView`.
|
|
186
|
+
|
|
187
|
+
You can customize this behavior by overriding `phlex_view_path` in your controller:
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
class UsersController
|
|
191
|
+
include Phlexible::Rails::ActionController::ImplicitRender
|
|
192
|
+
|
|
193
|
+
private
|
|
194
|
+
|
|
195
|
+
def phlex_view_path(action_name)
|
|
196
|
+
"views/#{controller_path}/#{action_name}"
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
This would resolve `UsersController#index` to `Views::Users::Index` instead.
|
|
86
202
|
|
|
87
|
-
|
|
203
|
+
### `Rails::ControllerVariables`
|
|
88
204
|
|
|
89
205
|
> **NOTE:** Prior to **1.0.0**, this module was called `ControllerAttributes` with a very different API. This is no longer available since **1.0.0**.
|
|
90
206
|
|
|
@@ -102,7 +218,7 @@ class Views::Users::Index < Views::Base
|
|
|
102
218
|
end
|
|
103
219
|
```
|
|
104
220
|
|
|
105
|
-
|
|
221
|
+
#### Options
|
|
106
222
|
|
|
107
223
|
`controller_variable` accepts one or many symbols, or a hash of symbols to options.
|
|
108
224
|
|
|
@@ -127,38 +243,103 @@ end
|
|
|
127
243
|
|
|
128
244
|
Please note that defining a variable with the same name as an existing variable in the view will be overwritten.
|
|
129
245
|
|
|
130
|
-
|
|
246
|
+
### `Rails::AutoLayout`
|
|
131
247
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Just include it in your ApplicationResponder:
|
|
248
|
+
Automatically wraps Phlex views in a layout component based on namespace conventions. Include this module in your view classes to enable automatic layout resolution.
|
|
135
249
|
|
|
136
250
|
```ruby
|
|
137
|
-
class
|
|
138
|
-
include Phlexible::Rails::
|
|
139
|
-
|
|
251
|
+
class Views::Admin::Index < Phlex::HTML
|
|
252
|
+
include Phlexible::Rails::AutoLayout
|
|
253
|
+
|
|
254
|
+
def view_template
|
|
255
|
+
span { 'admin index' }
|
|
256
|
+
end
|
|
140
257
|
end
|
|
141
258
|
```
|
|
142
259
|
|
|
143
|
-
|
|
260
|
+
#### Layout Resolution
|
|
261
|
+
|
|
262
|
+
Layouts are resolved by mapping the view's namespace to a layout class under `Views::Layouts::`. For example:
|
|
263
|
+
|
|
264
|
+
| View class | Layout resolved |
|
|
265
|
+
|---|---|
|
|
266
|
+
| `Views::Admin::Index` | `Views::Layouts::Admin` |
|
|
267
|
+
| `Views::Admin::Users::Show` | `Views::Layouts::Admin::Users` (falls back to `Views::Layouts::Admin` if not found) |
|
|
268
|
+
| `Views::Dashboard::Index` | `Views::Layouts::Application` (default fallback) |
|
|
269
|
+
|
|
270
|
+
Layout classes receive the view instance as a constructor argument and yield the view content:
|
|
144
271
|
|
|
145
272
|
```ruby
|
|
146
|
-
class
|
|
147
|
-
def
|
|
148
|
-
|
|
273
|
+
class Views::Layouts::Admin < Phlex::HTML
|
|
274
|
+
def initialize(view)
|
|
275
|
+
@view = view
|
|
149
276
|
end
|
|
150
277
|
|
|
278
|
+
def view_template(&block)
|
|
279
|
+
div(id: 'admin-layout', &block)
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### Controller-Assigned Layouts
|
|
285
|
+
|
|
286
|
+
You can override automatic resolution by setting a `@layout` instance variable in your controller. The view must also include `ViewAssigns` (which `AutoLayout` includes automatically):
|
|
287
|
+
|
|
288
|
+
```ruby
|
|
289
|
+
class AdminController < ApplicationController
|
|
151
290
|
def index
|
|
152
|
-
|
|
291
|
+
@layout = Views::Layouts::Custom
|
|
153
292
|
end
|
|
154
293
|
end
|
|
155
294
|
```
|
|
156
295
|
|
|
157
|
-
|
|
296
|
+
#### Configuration
|
|
297
|
+
|
|
298
|
+
Three class attributes control layout resolution:
|
|
158
299
|
|
|
159
|
-
|
|
300
|
+
| Attribute | Default | Description |
|
|
301
|
+
|---|---|---|
|
|
302
|
+
| `auto_layout_view_prefix` | `'Views::'` | Only views matching this prefix get auto-layout. Set to `nil` to match all view classes. |
|
|
303
|
+
| `auto_layout_namespace` | `'Views::Layouts::'` | Namespace where layout classes are looked up. |
|
|
304
|
+
| `auto_layout_default` | `'Views::Layouts::Application'` | Fallback layout when no namespace match is found. Set to `nil` to render without a layout. |
|
|
160
305
|
|
|
161
|
-
|
|
306
|
+
```ruby
|
|
307
|
+
class Views::Base < Phlex::HTML
|
|
308
|
+
include Phlexible::Rails::AutoLayout
|
|
309
|
+
|
|
310
|
+
self.auto_layout_view_prefix = 'Views::'
|
|
311
|
+
self.auto_layout_namespace = 'Views::Layouts::'
|
|
312
|
+
self.auto_layout_default = 'Views::Layouts::Application'
|
|
313
|
+
end
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### Layout Callbacks
|
|
317
|
+
|
|
318
|
+
When `Rails::AutoLayout` is included, `before_layout`, `after_layout`, and `around_layout` callbacks become available (provided by the `Callbacks` module):
|
|
319
|
+
|
|
320
|
+
```ruby
|
|
321
|
+
class Views::Admin::Index < Phlex::HTML
|
|
322
|
+
include Phlexible::Rails::AutoLayout
|
|
323
|
+
|
|
324
|
+
before_layout :log_render
|
|
325
|
+
|
|
326
|
+
def view_template
|
|
327
|
+
span { 'admin index' }
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
private
|
|
331
|
+
|
|
332
|
+
def log_render
|
|
333
|
+
Rails.logger.info "Rendering with layout"
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### Caching
|
|
339
|
+
|
|
340
|
+
Layout resolution is cached per class in production. In development (when `Rails.configuration.enable_reloading` is enabled), layouts are resolved fresh on each render. You can manually clear the cache with `reset_resolved_layout!`.
|
|
341
|
+
|
|
342
|
+
### `Rails::AElement`
|
|
162
343
|
|
|
163
344
|
No need to call Rails `link_to` helper, when you can simply render an anchor tag directly with Phlex. But unfortunately that means you lose some of the magic that `link_to` provides. Especially the automatic resolution of URL's and Rails routes.
|
|
164
345
|
|
|
@@ -180,7 +361,13 @@ class MyView < Phlex::HTML
|
|
|
180
361
|
end
|
|
181
362
|
```
|
|
182
363
|
|
|
183
|
-
|
|
364
|
+
You can also pass `:back` as the `href` value, which will use the referrer URL if available, or fall back to `javascript:history.back()`:
|
|
365
|
+
|
|
366
|
+
```ruby
|
|
367
|
+
a(href: :back) { 'Go back' }
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### `Rails::ButtonTo`
|
|
184
371
|
|
|
185
372
|
Generates a form containing a single button that submits to the URL created by the set of options.
|
|
186
373
|
|
|
@@ -198,7 +385,7 @@ The form submits a POST request by default. You can specify a different HTTP ver
|
|
|
198
385
|
Phlexible::Rails::ButtonTo.new(:root, method: :patch) { 'My Button' }
|
|
199
386
|
```
|
|
200
387
|
|
|
201
|
-
|
|
388
|
+
#### Options
|
|
202
389
|
|
|
203
390
|
- `:class` - Specify the HTML class name of the button (not the form).
|
|
204
391
|
- `:form_attributes` - Hash of HTML attributes for the form tag.
|
|
@@ -207,9 +394,7 @@ Phlexible::Rails::ButtonTo.new(:root, method: :patch) { 'My Button' }
|
|
|
207
394
|
- `:method` - Symbol of the HTTP verb. Supported verbs are :post (default), :get, :delete, :patch,
|
|
208
395
|
and :put.
|
|
209
396
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
> Available in **>= 1.0.0**
|
|
397
|
+
### `Rails::MetaTags`
|
|
213
398
|
|
|
214
399
|
A super simple way to define and render meta tags in your Phlex views. Just render the
|
|
215
400
|
`Phlexible::Rails::MetaTagsComponent` component in the head element of your page, and define the
|
|
@@ -237,98 +422,36 @@ class MyView < Phlex::HTML
|
|
|
237
422
|
end
|
|
238
423
|
```
|
|
239
424
|
|
|
240
|
-
### `
|
|
241
|
-
|
|
242
|
-
Create an alias at a given `element`, to the given view class.
|
|
425
|
+
### `Rails::Responder`
|
|
243
426
|
|
|
244
|
-
|
|
427
|
+
If you use [Responders](https://github.com/heartcombo/responders), Phlexible provides a responder to support implicit rendering similar to `Rails::ActionController::ImplicitRender` above. It will render the Phlex view using `respond_with` if one exists, and fall back to default rendering.
|
|
245
428
|
|
|
246
|
-
|
|
247
|
-
class MyView < Phlex::HTML
|
|
248
|
-
def view_template
|
|
249
|
-
div do
|
|
250
|
-
render My::Awesome::Component.new
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
end
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
You can instead do:
|
|
257
|
-
|
|
258
|
-
```ruby
|
|
259
|
-
class MyView < Phlex::HTML
|
|
260
|
-
extend Phlexible::AliasView
|
|
261
|
-
|
|
262
|
-
alias_view :awesome, -> { My::Awesome::Component }
|
|
263
|
-
|
|
264
|
-
def view_template
|
|
265
|
-
div do
|
|
266
|
-
awesome
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
end
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### PageTitle
|
|
273
|
-
|
|
274
|
-
Helper to assist in defining page titles within Phlex views. Also includes support for nested views, where each desendent view class will have its title prepended to the page title. Simply include *Phlexible::PageTitle* module and assign the title to the `page_title` class variable:
|
|
429
|
+
Just include it in your ApplicationResponder:
|
|
275
430
|
|
|
276
431
|
```ruby
|
|
277
|
-
class
|
|
278
|
-
|
|
432
|
+
class ApplicationResponder < ActionController::Responder
|
|
433
|
+
include Phlexible::Rails::ActionController::ImplicitRender
|
|
434
|
+
include Phlexible::Rails::Responder
|
|
279
435
|
end
|
|
280
436
|
```
|
|
281
437
|
|
|
282
|
-
Then
|
|
283
|
-
|
|
284
|
-
### `ProcessAttributes`
|
|
285
|
-
|
|
286
|
-
> This functionality is already built in to **Phlex >= 1**. This module is only needed for **Phlex >= 2**.
|
|
287
|
-
|
|
288
|
-
Allows you to intercept and modify HTML element attributes before they are rendered. This is useful for adding default attributes, transforming values, or conditionally modifying attributes based on other attributes.
|
|
289
|
-
|
|
290
|
-
Extend your view class with `Phlexible::ProcessAttributes` and define a `process_attributes` instance method that receives the attributes hash and returns the modified hash.
|
|
438
|
+
Then simply `respond_with` in your action method as normal:
|
|
291
439
|
|
|
292
440
|
```ruby
|
|
293
|
-
class
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
def process_attributes(attrs)
|
|
297
|
-
# Add a default class to all elements
|
|
298
|
-
attrs[:class] ||= 'my-default-class'
|
|
299
|
-
attrs
|
|
441
|
+
class UsersController < ApplicationController
|
|
442
|
+
def new
|
|
443
|
+
respond_with User.new
|
|
300
444
|
end
|
|
301
445
|
|
|
302
|
-
def
|
|
303
|
-
|
|
446
|
+
def index
|
|
447
|
+
respond_with User.all
|
|
304
448
|
end
|
|
305
449
|
end
|
|
306
450
|
```
|
|
307
451
|
|
|
308
|
-
This
|
|
309
|
-
|
|
310
|
-
```html
|
|
311
|
-
<div id="container" class="my-default-class">Hello</div>
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
The `process_attributes` method is called for all standard HTML elements and void elements, as well as any custom elements registered with `register_element`.
|
|
315
|
-
|
|
316
|
-
```ruby
|
|
317
|
-
class MyView < Phlex::HTML
|
|
318
|
-
extend Phlexible::ProcessAttributes
|
|
319
|
-
|
|
320
|
-
register_element :my_custom_element
|
|
321
|
-
|
|
322
|
-
def process_attributes(attrs)
|
|
323
|
-
attrs[:data_processed] = true
|
|
324
|
-
attrs
|
|
325
|
-
end
|
|
452
|
+
This responder requires the use of `ActionController::ImplicitRender`, so don't forget to include that in your `ApplicationController`.
|
|
326
453
|
|
|
327
|
-
|
|
328
|
-
my_custom_element(name: 'test') { 'Custom content' }
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
```
|
|
454
|
+
If you use `Rails::ControllerVariables` in your view, and define a `resource` attribute, the responder will pass that to your view.
|
|
332
455
|
|
|
333
456
|
## Development
|
|
334
457
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
phlexible (3.
|
|
4
|
+
phlexible (3.3.0)
|
|
5
5
|
phlex (>= 1.10.0, < 3.0.0)
|
|
6
6
|
phlex-rails (>= 1.2.0, < 3.0.0)
|
|
7
7
|
rails (>= 7.2.0, < 9.0.0)
|
|
@@ -416,7 +416,7 @@ CHECKSUMS
|
|
|
416
416
|
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
417
417
|
phlex (1.11.0) sha256=979548e79a205c981612f1ab613addc8fa128c8092694d02f41aad4cea905e73
|
|
418
418
|
phlex-rails (1.2.2) sha256=a20218449e71bc9fa5a71b672fbede8a654c6b32a58f1c4ea83ddc1682307a4c
|
|
419
|
-
phlexible (3.
|
|
419
|
+
phlexible (3.3.0)
|
|
420
420
|
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
421
421
|
pretty_please (0.2.0) sha256=1f00296f946ae8ffd53db25803ed3998d615b9cc07526517dc75fcca6af3a0d3
|
|
422
422
|
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
phlexible (3.
|
|
4
|
+
phlexible (3.3.0)
|
|
5
5
|
phlex (>= 1.10.0, < 3.0.0)
|
|
6
6
|
phlex-rails (>= 1.2.0, < 3.0.0)
|
|
7
7
|
rails (>= 7.2.0, < 9.0.0)
|
|
@@ -414,7 +414,7 @@ CHECKSUMS
|
|
|
414
414
|
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
415
415
|
phlex (1.11.0) sha256=979548e79a205c981612f1ab613addc8fa128c8092694d02f41aad4cea905e73
|
|
416
416
|
phlex-rails (1.2.2) sha256=a20218449e71bc9fa5a71b672fbede8a654c6b32a58f1c4ea83ddc1682307a4c
|
|
417
|
-
phlexible (3.
|
|
417
|
+
phlexible (3.3.0)
|
|
418
418
|
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
419
419
|
pretty_please (0.2.0) sha256=1f00296f946ae8ffd53db25803ed3998d615b9cc07526517dc75fcca6af3a0d3
|
|
420
420
|
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
phlexible (3.
|
|
4
|
+
phlexible (3.3.0)
|
|
5
5
|
phlex (>= 1.10.0, < 3.0.0)
|
|
6
6
|
phlex-rails (>= 1.2.0, < 3.0.0)
|
|
7
7
|
rails (>= 7.2.0, < 9.0.0)
|
|
@@ -422,7 +422,7 @@ CHECKSUMS
|
|
|
422
422
|
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
423
423
|
phlex (2.4.0) sha256=8aad2f0cd792d7b1bd287f15a1f89474c9cacac28120dc33d2a81467ae934067
|
|
424
424
|
phlex-rails (2.4.0) sha256=2bcddbd488681acb25753bab1887d3ac150e644244ff8ba307f2171a4d0195f5
|
|
425
|
-
phlexible (3.
|
|
425
|
+
phlexible (3.3.0)
|
|
426
426
|
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
427
427
|
pretty_please (0.2.0) sha256=1f00296f946ae8ffd53db25803ed3998d615b9cc07526517dc75fcca6af3a0d3
|
|
428
428
|
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
phlexible (3.
|
|
4
|
+
phlexible (3.3.0)
|
|
5
5
|
phlex (>= 1.10.0, < 3.0.0)
|
|
6
6
|
phlex-rails (>= 1.2.0, < 3.0.0)
|
|
7
7
|
rails (>= 7.2.0, < 9.0.0)
|
|
@@ -420,7 +420,7 @@ CHECKSUMS
|
|
|
420
420
|
parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
|
|
421
421
|
phlex (2.4.0) sha256=8aad2f0cd792d7b1bd287f15a1f89474c9cacac28120dc33d2a81467ae934067
|
|
422
422
|
phlex-rails (2.4.0) sha256=2bcddbd488681acb25753bab1887d3ac150e644244ff8ba307f2171a4d0195f5
|
|
423
|
-
phlexible (3.
|
|
423
|
+
phlexible (3.3.0)
|
|
424
424
|
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
425
425
|
pretty_please (0.2.0) sha256=1f00296f946ae8ffd53db25803ed3998d615b9cc07526517dc75fcca6af3a0d3
|
|
426
426
|
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
data/lib/phlexible/callbacks.rb
CHANGED
|
@@ -33,6 +33,18 @@ module Phlexible
|
|
|
33
33
|
def after_template(*names, &block)
|
|
34
34
|
set_callback(:template, :after, *names, &block)
|
|
35
35
|
end
|
|
36
|
+
|
|
37
|
+
def before_layout(*names, &block)
|
|
38
|
+
set_callback(:layout, :before, *names, &block)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def after_layout(*names, &block)
|
|
42
|
+
set_callback(:layout, :after, *names, &block)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def around_layout(*names, &block)
|
|
46
|
+
set_callback(:layout, :around, *names, &block)
|
|
47
|
+
end
|
|
36
48
|
end
|
|
37
49
|
|
|
38
50
|
def around_template
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'phlex/version'
|
|
4
|
+
|
|
3
5
|
module Phlexible
|
|
4
6
|
module Rails
|
|
5
|
-
# Calls `url_for` for the `href` attribute.
|
|
7
|
+
# Calls `url_for` for the `href` attribute, and supports a `:back` `href` value.
|
|
6
8
|
module AElement
|
|
7
9
|
extend ActiveSupport::Concern
|
|
8
10
|
|
|
@@ -10,9 +12,43 @@ module Phlexible
|
|
|
10
12
|
include Phlex::Rails::Helpers::URLFor
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
def a(href:,
|
|
14
|
-
|
|
15
|
+
def a(href:, **attrs, &)
|
|
16
|
+
attrs[:href] = href == :back ? _back_url : url_for(href)
|
|
17
|
+
|
|
18
|
+
super(**attrs, &)
|
|
15
19
|
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
JAVASCRIPT_BACK = 'javascript:history.back()'
|
|
24
|
+
private_constant :JAVASCRIPT_BACK
|
|
25
|
+
|
|
26
|
+
if Phlex::VERSION >= '2.0.0'
|
|
27
|
+
def _back_url
|
|
28
|
+
_filtered_referrer || safe(JAVASCRIPT_BACK)
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
# Wraps a value to bypass Phlex 1.x's javascript: href stripping.
|
|
32
|
+
SafeHref = Struct.new(:value) do
|
|
33
|
+
def to_phlex_attribute_value = value
|
|
34
|
+
def to_s = ''
|
|
35
|
+
end
|
|
36
|
+
private_constant :SafeHref
|
|
37
|
+
|
|
38
|
+
def _back_url
|
|
39
|
+
_filtered_referrer || SafeHref.new(JAVASCRIPT_BACK)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def _filtered_referrer # :nodoc:
|
|
44
|
+
controller = respond_to?(:view_context) ? view_context : helpers
|
|
45
|
+
|
|
46
|
+
if controller.respond_to?(:request)
|
|
47
|
+
referrer = controller.request.env['HTTP_REFERER']
|
|
48
|
+
referrer if referrer && URI(referrer).scheme != 'javascript'
|
|
49
|
+
end
|
|
50
|
+
rescue URI::InvalidURIError # rubocop:disable Lint/SuppressedException
|
|
51
|
+
end
|
|
16
52
|
end
|
|
17
53
|
end
|
|
18
54
|
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phlexible
|
|
4
|
+
module Rails
|
|
5
|
+
module AutoLayout
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
include Phlexible::Rails::ViewAssigns
|
|
8
|
+
include Phlexible::Callbacks
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
define_callbacks :layout
|
|
12
|
+
|
|
13
|
+
class_attribute :auto_layout_view_prefix, instance_writer: false, default: 'Views::'
|
|
14
|
+
class_attribute :auto_layout_namespace, instance_writer: false, default: 'Views::Layouts::'
|
|
15
|
+
class_attribute :auto_layout_default, instance_writer: false, default: 'Views::Layouts::Application'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def around_template
|
|
19
|
+
layout_class = controller_assigned_layout || self.class.resolved_layout
|
|
20
|
+
if layout_class
|
|
21
|
+
run_callbacks :layout do
|
|
22
|
+
render(@layout = layout_class.new(self)) { super }
|
|
23
|
+
end
|
|
24
|
+
else
|
|
25
|
+
super
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class_methods do
|
|
30
|
+
def resolved_layout
|
|
31
|
+
if ::Rails.configuration.enable_reloading
|
|
32
|
+
resolve_layout
|
|
33
|
+
else
|
|
34
|
+
return @resolved_layout if defined?(@resolved_layout)
|
|
35
|
+
|
|
36
|
+
@resolved_layout = resolve_layout
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reset_resolved_layout!
|
|
41
|
+
remove_instance_variable(:@resolved_layout) if defined?(@resolved_layout)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def resolve_layout
|
|
47
|
+
view_name = resolve_view_name
|
|
48
|
+
return nil if view_name.blank?
|
|
49
|
+
|
|
50
|
+
prefix = auto_layout_view_prefix
|
|
51
|
+
return nil if prefix && !view_name.start_with?(prefix)
|
|
52
|
+
|
|
53
|
+
resolve_layout_from_namespace(view_name, prefix) ||
|
|
54
|
+
auto_layout_default&.safe_constantize
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def resolve_layout_from_namespace(view_name, prefix)
|
|
58
|
+
strip_prefix = prefix || infer_prefix_from_namespace || ''
|
|
59
|
+
segments = view_name.delete_prefix(strip_prefix).split('::')[..-2]
|
|
60
|
+
|
|
61
|
+
segments.length.downto(1) do |i|
|
|
62
|
+
klass = "#{auto_layout_namespace}#{segments.first(i).join('::')}".safe_constantize
|
|
63
|
+
return klass if klass.is_a?(Class)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def infer_prefix_from_namespace
|
|
70
|
+
root = auto_layout_namespace&.split('::')&.first
|
|
71
|
+
"#{root}::" if root
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def resolve_view_name
|
|
75
|
+
ancestors.each do |ancestor|
|
|
76
|
+
return ancestor.name if ancestor.is_a?(Class) && ancestor.name.present?
|
|
77
|
+
end
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def controller_assigned_layout
|
|
85
|
+
return nil if !respond_to?(:view_assigns, true)
|
|
86
|
+
|
|
87
|
+
view_assigns['layout']
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/phlexible/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: phlexible
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joel Moss
|
|
@@ -91,9 +91,15 @@ executables: []
|
|
|
91
91
|
extensions: []
|
|
92
92
|
extra_rdoc_files: []
|
|
93
93
|
files:
|
|
94
|
+
- ".claude/agents/rubocop-reviewer.md"
|
|
95
|
+
- ".claude/hooks/protect-files.sh"
|
|
96
|
+
- ".claude/hooks/rubocop-check.sh"
|
|
97
|
+
- ".claude/settings.json"
|
|
98
|
+
- ".claude/skills/test/SKILL.md"
|
|
94
99
|
- ".rubocop.yml"
|
|
95
100
|
- ".ruby-version"
|
|
96
101
|
- Appraisals
|
|
102
|
+
- CLAUDE.md
|
|
97
103
|
- CODE_OF_CONDUCT.md
|
|
98
104
|
- LICENSE.txt
|
|
99
105
|
- README.md
|
|
@@ -115,6 +121,7 @@ files:
|
|
|
115
121
|
- lib/phlexible/rails/a_element.rb
|
|
116
122
|
- lib/phlexible/rails/action_controller/implicit_render.rb
|
|
117
123
|
- lib/phlexible/rails/action_controller/meta_tags.rb
|
|
124
|
+
- lib/phlexible/rails/auto_layout.rb
|
|
118
125
|
- lib/phlexible/rails/button_to.rb
|
|
119
126
|
- lib/phlexible/rails/button_to_concerns.rb
|
|
120
127
|
- lib/phlexible/rails/controller_variables.rb
|
|
@@ -144,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
144
151
|
- !ruby/object:Gem::Version
|
|
145
152
|
version: '0'
|
|
146
153
|
requirements: []
|
|
147
|
-
rubygems_version: 4.0.
|
|
154
|
+
rubygems_version: 4.0.6
|
|
148
155
|
specification_version: 4
|
|
149
156
|
summary: A bunch of helpers and goodies intended to make life with Phlex even easier!
|
|
150
157
|
test_files: []
|