webring-rails 1.7.6 → 1.8.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/README.md +48 -11
- data/app/assets/javascripts/webring/widget.js +15 -0
- data/app/assets/javascripts/webring/widget.min.js +1 -1
- data/app/controllers/webring/navigation_controller.rb +1 -1
- data/app/controllers/webring/widget_controller.rb +5 -0
- data/lib/webring/engine.rb +5 -0
- data/lib/webring/routing.rb +46 -0
- data/lib/webring/version.rb +1 -1
- data/lib/webring-rails.rb +1 -0
- metadata +3 -3
- data/config/routes.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7231dcbc5a185d6c345c5d13b387d09aa80dd5acd7962f8c006a9ca7f313a585
|
4
|
+
data.tar.gz: 6f377e0a118b9037fcd65f6b015000ff247ca3616e670abc3154dea86389be53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ea2a0284502cca42c7f1c9faa6cc7500158fc995e5d7d9f0481ffcc0c674794eff4f58197fa3bc9e24af0732e9fcdaf5bdc9f6c1fc94166ce8d8faa6c34dfa1
|
7
|
+
data.tar.gz: 7dbd23f1404bb811c4380fdd37e195fadde5c1212e1261baab4fc94df327350627453d537fa99a1bf452f69598854b3f93f08ff3d4198f9b283ff63d25ab27b3
|
data/README.md
CHANGED
@@ -6,14 +6,15 @@
|
|
6
6
|
|
7
7
|
## Features
|
8
8
|
|
9
|
-
- Complete MVC structure for managing webring members
|
10
|
-
- Circular navigation system between member websites
|
11
|
-
-
|
12
|
-
-
|
13
|
-
-
|
14
|
-
-
|
15
|
-
-
|
16
|
-
-
|
9
|
+
- **Complete MVC structure** for managing webring members
|
10
|
+
- **Circular navigation system** between member websites
|
11
|
+
- **One-line route configuration** with `webring_routes` helper (similar to Devise)
|
12
|
+
- **UID-based member identification** for security
|
13
|
+
- **Embeddable JavaScript widget** for easy member site integration
|
14
|
+
- **Customizable widget appearance** and behavior
|
15
|
+
- **Optional membership request system** for sites to apply to join the webring
|
16
|
+
- **Generators for easy setup** and customization
|
17
|
+
- **Extensible architecture** for adding custom features
|
17
18
|
|
18
19
|
## Installation
|
19
20
|
|
@@ -29,9 +30,6 @@ Run:
|
|
29
30
|
# Install the gem
|
30
31
|
bundle install
|
31
32
|
|
32
|
-
# Run the installation generator
|
33
|
-
rails generate webring:install
|
34
|
-
|
35
33
|
# Create the member model and migrations
|
36
34
|
rails generate webring:member
|
37
35
|
|
@@ -39,6 +37,18 @@ rails generate webring:member
|
|
39
37
|
rails generate webring:navigation_controller
|
40
38
|
```
|
41
39
|
|
40
|
+
### Configure Routes
|
41
|
+
|
42
|
+
Add the `webring_routes` helper to your `config/routes.rb`:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
# config/routes.rb
|
46
|
+
Rails.application.routes.draw do
|
47
|
+
webring_routes
|
48
|
+
# ... other routes
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
42
52
|
### Optional Features
|
43
53
|
|
44
54
|
```bash
|
@@ -55,6 +65,33 @@ Finally, run the migrations:
|
|
55
65
|
rails db:migrate
|
56
66
|
```
|
57
67
|
|
68
|
+
## Route Configuration
|
69
|
+
|
70
|
+
### Basic Usage
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
# Default configuration
|
74
|
+
webring_routes
|
75
|
+
```
|
76
|
+
|
77
|
+
### Custom Controllers
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
# Use custom controllers
|
81
|
+
webring_routes navigation: :custom_navigation, widget: :custom_widget
|
82
|
+
```
|
83
|
+
|
84
|
+
### Advanced Configuration
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
# Full customization
|
88
|
+
webring_routes(
|
89
|
+
navigation: :my_navigation,
|
90
|
+
widget: :my_widget,
|
91
|
+
mount_path: '/network'
|
92
|
+
)
|
93
|
+
```
|
94
|
+
|
58
95
|
## Documentation
|
59
96
|
|
60
97
|
For detailed documentation on models, controllers, modules, widget customization, and more advanced installation options, please visit the [Webring Rails Wiki](https://github.com/lstpsche/webring-rails/wiki).
|
@@ -472,6 +472,21 @@
|
|
472
472
|
|
473
473
|
container.innerHTML = '';
|
474
474
|
container.appendChild(fragment);
|
475
|
+
|
476
|
+
const widgetFetchMetricsPath = "<<REPLACE_ME_WIDGET_FETCH_METRICS_PATH>>";
|
477
|
+
|
478
|
+
if (widgetFetchMetricsPath && widgetFetchMetricsPath.trim() !== '' && widgetFetchMetricsPath.trim() !== '<<REPLACE_ME_WIDGET_FETCH_METRICS_PATH>>') { // if not empty and not the default value
|
479
|
+
// Track widget fetch for metrics
|
480
|
+
try {
|
481
|
+
fetch(`${baseUrl}${widgetFetchMetricsPath}`, {
|
482
|
+
method: 'POST',
|
483
|
+
headers: {
|
484
|
+
'Content-Type': 'application/json'
|
485
|
+
},
|
486
|
+
body: JSON.stringify({ uid: memberUid })
|
487
|
+
}).catch(() => {}); // Silently fail if metrics tracking fails - don't break the widget
|
488
|
+
} catch (error) {} // Silently fail if fetch is not supported or other errors occur
|
489
|
+
}
|
475
490
|
};
|
476
491
|
|
477
492
|
function applyStyles(styleOption) {
|
@@ -1 +1 @@
|
|
1
|
-
!function(){function n(n){function t(n){let t=document.getElementById(e.STYLE_ID);switch(t||(t=document.createElement("style"),t.id=e.STYLE_ID,document.head.insertBefore(t,document.head.firstChild)),n){case"none":t.textContent=d.reset;break;case"layout":t.textContent=d.reset+d.layout;break;default:t.textContent=d.reset+d.layout+d.design}}const r=n||document.currentScript||document.getElementsByTagName("script")[document.getElementsByTagName("script").length-1];if(!r)return;const i=r.getAttribute("data-member-uid"),s=r.getAttribute("data-widget-type")??e.DEFAULT_TYPE,f=r.getAttribute("data-target-id")??e.DEFAULT_TARGET_ID,w="false"!==r.getAttribute("data-button-text"),c=r.getAttribute("data-styles")??e.DEFAULT_STYLE_TYPE,m=e.VALID_STYLE_TYPES.includes(c)?c:e.DEFAULT_STYLE_TYPE,x=r.getAttribute("data-theme")??e.DEFAULT_THEME,v=e.VALID_THEMES.includes(x)?x:e.DEFAULT_THEME,p=r.getAttribute("data-prev-text"),h=r.getAttribute("data-random-text"),u=r.getAttribute("data-next-text"),E=r.getAttribute("data-widget-text");if(!i)return void console.error("Webring Widget: Missing data-member-uid attribute on script tag.");if(!e.VALID_TYPES.includes(s))return void console.error(`Webring Widget: Invalid widget type "${s}". Valid types: ${e.VALID_TYPES.join(", ")}`);const y=r.getAttribute("src"),T=new URL(y,window.location.href).origin,_=function(){const n=document.getElementById(f);if(!n)return void console.error(`Webring Widget: No element with id "${f}" found.`);l||(t(m),l=!0);const e=document.createDocumentFragment(),r=document.createElement("div");r.className="webring-nav",r.setAttribute("data-widget-type",s),r.setAttribute("data-button-text",w.toString()),r.setAttribute("data-theme",v);const d={prev:b.prev.text_enforced?b.prev:p?{...b.prev,text:`\xab ${p}`}:b.prev,random:b.random.text_enforced?b.random:h&&""!==h.trim()?{...b.random,text:`${o(20,20,"margin-right: 4px; margin-top: 1px;")} ${h}`}:b.random,next:b.next.text_enforced?b.next:u?{...b.next,text:`${u} \xbb`}:b.next,logoOnly:b.logoOnly},c=g[s];if(c.showTitle){const n=document.createElement("a");n.href=T,n.className="webring-title",n.innerHTML=a.widgetTitle.enforced?a.widgetTitle.default:E??a.widgetTitle.default,r.appendChild(n)}const x=document.createElement("nav");x.className="webring-buttons",c.actions.forEach((n=>{const e=d[n];if("logoOnly"===n){const n=document.createElement("div");return n.className=e.additionalClass,n.innerHTML=e.symbol,void x.appendChild(n)}const t=document.createElement("a");if(t.href=`${T}/webring/${e.path}?source_member_uid=${i}`,t.title=e.title,t.className=`webring-btn ${e.additionalClass}`,"one-way"===s&&c.showLogoInButton&&"next"===n){const n=b.next.text_enforced?a.next.default:u||d.next.text.replace(" \xbb","");t.innerHTML=w?`<span class="webring-logo-inline">${o(20,20)}</span> ${n} \xbb`:`<span class="webring-logo-inline">${o(20,20)}</span> ${e.symbol}`}else"random"!==n||!w||""!==h?.trim()&&void 0!==h?.trim()?t.innerHTML=w?e.text:e.symbol:t.innerHTML=o(23,23,"margin-top: 1px;");x.appendChild(t)})),r.appendChild(x),e.appendChild(r),n.innerHTML="",n.appendChild(e)};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",_):_()}const e=Object.freeze({VALID_TYPES:Object.freeze(["full","no-text","two-way","one-way","random-only"]),DEFAULT_TYPE:"full",DEFAULT_TARGET_ID:"webring-widget",STYLE_ID:"webring-widget-styles",VALID_STYLE_TYPES:Object.freeze(["full","layout","none"]),DEFAULT_STYLE_TYPE:"full",VALID_THEMES:Object.freeze(["light","dark"]),DEFAULT_THEME:"light"}),t=Object.freeze({prev:{default:"\xab Prev",enforced:!1},random:{default:"Random",enforced:!1},next:{default:"Next \xbb",enforced:!1},widgetTitle:{default:"Webring",enforced:!1}}),r="<<REPLACE_ME_TEXT_DEFAULTS>>",i="<<REPLACE_ME_TEXT_DEFAULTS>>"!==r?"string"==typeof r?JSON.parse(r):r:{},a=Object.freeze(Object.keys(t).reduce(((n,e)=>{const r=i[e];return n[e]={default:r?.default??t[e].default,enforced:r?.enforced??t[e].enforced},n}),{})),o="<<REPLACE_ME_LOGO_SVG_FUNCTION>>",b=Object.freeze({prev:{symbol:"\xab",text:a.prev.default,text_enforced:a.prev.enforced,title:"Previous site",path:"previous",additionalClass:"prev-btn"},random:{symbol:o(23,23),text:`${o(20,20,"margin-right: 4px; margin-top: 1px;")} ${a.random.default}`,text_enforced:a.random.enforced,title:"Random site",path:"random",additionalClass:"random-btn"},next:{symbol:"\xbb",text:a.next.default,text_enforced:a.next.enforced,title:"Next site",path:"next",additionalClass:"next-btn"},logoOnly:{symbol:o(23,23),text:o(23,23),path:"",additionalClass:"logo-only"}}),g=Object.freeze({full:{showTitle:!0,actions:["prev","random","next"]},"no-text":{showTitle:!1,actions:["prev","random","next"]},"two-way":{showTitle:!1,actions:["prev","logoOnly","next"],showLogoInMiddle:!0},"one-way":{showTitle:!1,actions:["next"],showLogoInButton:!0},"random-only":{showTitle:!1,actions:["random"]}}),d=Object.freeze({reset:"\n .webring-nav,\n .webring-nav div,\n .webring-nav span,\n .webring-nav nav,\n .webring-nav a,\n .webring-nav div::before,\n .webring-nav span::before,\n .webring-nav nav::before,\n .webring-nav a::before,\n .webring-nav div::after,\n .webring-nav span::after,\n .webring-nav nav::after,\n .webring-nav a::after {\n all: initial;\n box-sizing: border-box;\n }\n\n .webring-nav,\n .webring-nav div,\n .webring-nav span,\n .webring-nav nav,\n .webring-nav a {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n color: inherit;\n }\n\n .webring-nav div,\n .webring-nav span,\n .webring-nav nav,\n .webring-nav a {\n display: initial;\n margin: 0;\n padding: 0;\n border: none;\n background: none;\n text-decoration: none;\n color: inherit;\n font-weight: inherit;\n font-size: inherit;\n line-height: inherit;\n vertical-align: baseline;\n box-shadow: none;\n outline: none;\n transform: none;\n opacity: 1;\n visibility: visible;\n position: static;\n float: none;\n clear: none;\n overflow: visible;\n white-space: normal;\n text-align: left;\n letter-spacing: normal;\n word-spacing: normal;\n text-transform: none;\n text-shadow: none;\n list-style: none;\n border-radius: 0;\n min-width: auto;\n max-width: none;\n min-height: auto;\n max-height: none;\n width: auto;\n height: auto;\n top: auto;\n right: auto;\n bottom: auto;\n left: auto;\n z-index: auto;\n }\n\n .webring-nav a {\n cursor: pointer;\n }\n ",layout:'\n .webring-nav {\n font-family: var(--webring-font-family);\n font-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: center;\n max-width: 350px;\n margin: 0 auto;\n padding: 10px;\n box-sizing: border-box;\n }\n .webring-nav .webring-title {\n margin: 0 0 8px 0;\n padding: 0;\n font-size: inherit;\n line-height: 24px;\n text-decoration: none;\n color: inherit;\n cursor: pointer;\n }\n .webring-nav nav {\n display: flex;\n gap: 10px;\n width: 100%;\n justify-content: center;\n align-items: center;\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n .webring-nav .webring-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 6px 12px;\n text-decoration: none;\n box-sizing: border-box;\n margin: 0;\n line-height: 24px;\n }\n .webring-nav .webring-btn.random-btn {\n padding: 6px 8px;\n }\n .webring-nav nav .logo-only {\n padding: 8px 3px 6px 3px;\n margin: 0;\n }\n .webring-nav[data-widget-type="no-text"] {\n padding: 8px 10px;\n }\n .webring-nav[data-widget-type="one-way"] {\n max-width: 200px;\n }\n .webring-nav .webring-logo-inline {\n display: inline-block;\n vertical-align: middle;\n margin: 1px 6px 0 0;\n }\n .webring-nav[data-button-text="false"] .prev-btn {\n padding: 5px 12.5px 6px 12px;\n }\n .webring-nav[data-button-text="false"] .next-btn {\n padding: 5px 12px 6px 12.5px;\n }\n ',design:'\n /* CSS Custom Properties for easy theming */\n .webring-nav {\n /* Internal variables that use public API with fallbacks */\n --webring-font-family: var(--webring-theme-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);\n --webring-bg-color: var(--webring-theme-bg);\n --webring-border-color: var(--webring-theme-border);\n --webring-text-color: var(--webring-theme-text);\n --webring-btn-bg: var(--webring-theme-btn-bg);\n --webring-btn-border: var(--webring-theme-btn-border);\n --webring-btn-text: var(--webring-theme-btn-text);\n --webring-btn-hover-bg: var(--webring-theme-btn-hover-bg);\n --webring-btn-hover-text: var(--webring-theme-btn-hover-text);\n }\n\n /* Common theme styles using CSS variables */\n .webring-nav {\n background-color: var(--webring-bg-color);\n }\n .webring-nav[data-widget-type="full"] {\n border: 2.5px solid var(--webring-border-color);\n }\n .webring-nav .webring-title {\n font-weight: 600;\n color: var(--webring-text-color);\n }\n .webring-nav .webring-btn {\n text-wrap: nowrap;\n font-weight: 600;\n color: var(--webring-btn-text);\n background-color: var(--webring-btn-bg);\n border: 2.5px solid var(--webring-btn-border);\n transition: background-color 0.2s ease, color 0.2s ease;\n }\n .webring-nav .webring-btn:focus {\n outline: none;\n background-color: transparent;\n color: var(--webring-btn-text);\n }\n .webring-nav .webring-btn:hover,\n .webring-nav .webring-btn:active {\n background-color: var(--webring-btn-hover-bg);\n color: var(--webring-btn-hover-text);\n }\n .webring-nav svg {\n fill: currentColor;\n }\n\n /* Light theme defaults */\n .webring-nav {\n --webring-theme-bg: #ffffff;\n --webring-theme-border: #000000;\n --webring-theme-text: #000000;\n --webring-theme-btn-bg: #ffffff;\n --webring-theme-btn-border: #000000;\n --webring-theme-btn-text: #000000;\n --webring-theme-btn-hover-bg: #000000;\n --webring-theme-btn-hover-text: #ffffff;\n }\n\n /* Dark theme overrides */\n .webring-nav[data-theme="dark"] {\n --webring-theme-bg: #000000;\n --webring-theme-border: #ffffff;\n --webring-theme-text: #ffffff;\n --webring-theme-btn-bg: #000000;\n --webring-theme-btn-border: #ffffff;\n --webring-theme-btn-text: #ffffff;\n --webring-theme-btn-hover-bg: #ffffff;\n --webring-theme-btn-hover-text: #000000;\n }\n '});let l=!1;n()}();
|
1
|
+
!function(){function n(n){function t(n){let t=document.getElementById(e.STYLE_ID);switch(t||(t=document.createElement("style"),t.id=e.STYLE_ID,document.head.insertBefore(t,document.head.firstChild)),n){case"none":t.textContent=g.reset;break;case"layout":t.textContent=g.reset+g.layout;break;default:t.textContent=g.reset+g.layout+g.design}}const r=n||document.currentScript||document.getElementsByTagName("script")[document.getElementsByTagName("script").length-1];if(!r)return;const i=r.getAttribute("data-member-uid"),s=r.getAttribute("data-widget-type")??e.DEFAULT_TYPE,c=r.getAttribute("data-target-id")??e.DEFAULT_TARGET_ID,f="false"!==r.getAttribute("data-button-text"),w=r.getAttribute("data-styles")??e.DEFAULT_STYLE_TYPE,m=e.VALID_STYLE_TYPES.includes(w)?w:e.DEFAULT_STYLE_TYPE,x=r.getAttribute("data-theme")??e.DEFAULT_THEME,p=e.VALID_THEMES.includes(x)?x:e.DEFAULT_THEME,v=r.getAttribute("data-prev-text"),h=r.getAttribute("data-random-text"),u=r.getAttribute("data-next-text"),E=r.getAttribute("data-widget-text");if(!i)return void console.error("Webring Widget: Missing data-member-uid attribute on script tag.");if(!e.VALID_TYPES.includes(s))return void console.error(`Webring Widget: Invalid widget type "${s}". Valid types: ${e.VALID_TYPES.join(", ")}`);const T=r.getAttribute("src"),y=new URL(T,window.location.href).origin,_=function(){const n=document.getElementById(c);if(!n)return void console.error(`Webring Widget: No element with id "${c}" found.`);l||(t(m),l=!0);const e=document.createDocumentFragment(),r=document.createElement("div");r.className="webring-nav",r.setAttribute("data-widget-type",s),r.setAttribute("data-button-text",f.toString()),r.setAttribute("data-theme",p);const g={prev:b.prev.text_enforced?b.prev:v?{...b.prev,text:`\xab ${v}`}:b.prev,random:b.random.text_enforced?b.random:h&&""!==h.trim()?{...b.random,text:`${o(20,20,"margin-right: 4px; margin-top: 1px;")} ${h}`}:b.random,next:b.next.text_enforced?b.next:u?{...b.next,text:`${u} \xbb`}:b.next,logoOnly:b.logoOnly},w=d[s];if(w.showTitle){const n=document.createElement("a");n.href=y,n.className="webring-title",n.innerHTML=a.widgetTitle.enforced?a.widgetTitle.default:E??a.widgetTitle.default,r.appendChild(n)}const x=document.createElement("nav");x.className="webring-buttons",w.actions.forEach((n=>{const e=g[n];if("logoOnly"===n){const n=document.createElement("div");return n.className=e.additionalClass,n.innerHTML=e.symbol,void x.appendChild(n)}const t=document.createElement("a");if(t.href=`${y}/webring/${e.path}?source_member_uid=${i}`,t.title=e.title,t.className=`webring-btn ${e.additionalClass}`,"one-way"===s&&w.showLogoInButton&&"next"===n){const n=b.next.text_enforced?a.next.default:u||g.next.text.replace(" \xbb","");t.innerHTML=f?`<span class="webring-logo-inline">${o(20,20)}</span> ${n} \xbb`:`<span class="webring-logo-inline">${o(20,20)}</span> ${e.symbol}`}else"random"!==n||!f||""!==h?.trim()&&void 0!==h?.trim()?t.innerHTML=f?e.text:e.symbol:t.innerHTML=o(23,23,"margin-top: 1px;");x.appendChild(t)})),r.appendChild(x),e.appendChild(r),n.innerHTML="",n.appendChild(e);const T="<<REPLACE_ME_WIDGET_FETCH_METRICS_PATH>>";if(T&&""!==T.trim()&&"<<REPLACE_ME_WIDGET_FETCH_METRICS_PATH>>"!==T.trim())try{fetch(`${y}${T}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({uid:i})}).catch((()=>{}))}catch(n){}};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",_):_()}const e=Object.freeze({VALID_TYPES:Object.freeze(["full","no-text","two-way","one-way","random-only"]),DEFAULT_TYPE:"full",DEFAULT_TARGET_ID:"webring-widget",STYLE_ID:"webring-widget-styles",VALID_STYLE_TYPES:Object.freeze(["full","layout","none"]),DEFAULT_STYLE_TYPE:"full",VALID_THEMES:Object.freeze(["light","dark"]),DEFAULT_THEME:"light"}),t=Object.freeze({prev:{default:"\xab Prev",enforced:!1},random:{default:"Random",enforced:!1},next:{default:"Next \xbb",enforced:!1},widgetTitle:{default:"Webring",enforced:!1}}),r="<<REPLACE_ME_TEXT_DEFAULTS>>",i="<<REPLACE_ME_TEXT_DEFAULTS>>"!==r?"string"==typeof r?JSON.parse(r):r:{},a=Object.freeze(Object.keys(t).reduce(((n,e)=>{const r=i[e];return n[e]={default:r?.default??t[e].default,enforced:r?.enforced??t[e].enforced},n}),{})),o="<<REPLACE_ME_LOGO_SVG_FUNCTION>>",b=Object.freeze({prev:{symbol:"\xab",text:a.prev.default,text_enforced:a.prev.enforced,title:"Previous site",path:"previous",additionalClass:"prev-btn"},random:{symbol:o(23,23),text:`${o(20,20,"margin-right: 4px; margin-top: 1px;")} ${a.random.default}`,text_enforced:a.random.enforced,title:"Random site",path:"random",additionalClass:"random-btn"},next:{symbol:"\xbb",text:a.next.default,text_enforced:a.next.enforced,title:"Next site",path:"next",additionalClass:"next-btn"},logoOnly:{symbol:o(23,23),text:o(23,23),path:"",additionalClass:"logo-only"}}),d=Object.freeze({full:{showTitle:!0,actions:["prev","random","next"]},"no-text":{showTitle:!1,actions:["prev","random","next"]},"two-way":{showTitle:!1,actions:["prev","logoOnly","next"],showLogoInMiddle:!0},"one-way":{showTitle:!1,actions:["next"],showLogoInButton:!0},"random-only":{showTitle:!1,actions:["random"]}}),g=Object.freeze({reset:"\n .webring-nav,\n .webring-nav div,\n .webring-nav span,\n .webring-nav nav,\n .webring-nav a,\n .webring-nav div::before,\n .webring-nav span::before,\n .webring-nav nav::before,\n .webring-nav a::before,\n .webring-nav div::after,\n .webring-nav span::after,\n .webring-nav nav::after,\n .webring-nav a::after {\n all: initial;\n box-sizing: border-box;\n }\n\n .webring-nav,\n .webring-nav div,\n .webring-nav span,\n .webring-nav nav,\n .webring-nav a {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n color: inherit;\n }\n\n .webring-nav div,\n .webring-nav span,\n .webring-nav nav,\n .webring-nav a {\n display: initial;\n margin: 0;\n padding: 0;\n border: none;\n background: none;\n text-decoration: none;\n color: inherit;\n font-weight: inherit;\n font-size: inherit;\n line-height: inherit;\n vertical-align: baseline;\n box-shadow: none;\n outline: none;\n transform: none;\n opacity: 1;\n visibility: visible;\n position: static;\n float: none;\n clear: none;\n overflow: visible;\n white-space: normal;\n text-align: left;\n letter-spacing: normal;\n word-spacing: normal;\n text-transform: none;\n text-shadow: none;\n list-style: none;\n border-radius: 0;\n min-width: auto;\n max-width: none;\n min-height: auto;\n max-height: none;\n width: auto;\n height: auto;\n top: auto;\n right: auto;\n bottom: auto;\n left: auto;\n z-index: auto;\n }\n\n .webring-nav a {\n cursor: pointer;\n }\n ",layout:'\n .webring-nav {\n font-family: var(--webring-font-family);\n font-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: center;\n max-width: 350px;\n margin: 0 auto;\n padding: 10px;\n box-sizing: border-box;\n }\n .webring-nav .webring-title {\n margin: 0 0 8px 0;\n padding: 0;\n font-size: inherit;\n line-height: 24px;\n text-decoration: none;\n color: inherit;\n cursor: pointer;\n }\n .webring-nav nav {\n display: flex;\n gap: 10px;\n width: 100%;\n justify-content: center;\n align-items: center;\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n .webring-nav .webring-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 6px 12px;\n text-decoration: none;\n box-sizing: border-box;\n margin: 0;\n line-height: 24px;\n }\n .webring-nav .webring-btn.random-btn {\n padding: 6px 8px;\n }\n .webring-nav nav .logo-only {\n padding: 8px 3px 6px 3px;\n margin: 0;\n }\n .webring-nav[data-widget-type="no-text"] {\n padding: 8px 10px;\n }\n .webring-nav[data-widget-type="one-way"] {\n max-width: 200px;\n }\n .webring-nav .webring-logo-inline {\n display: inline-block;\n vertical-align: middle;\n margin: 1px 6px 0 0;\n }\n .webring-nav[data-button-text="false"] .prev-btn {\n padding: 5px 12.5px 6px 12px;\n }\n .webring-nav[data-button-text="false"] .next-btn {\n padding: 5px 12px 6px 12.5px;\n }\n ',design:'\n /* CSS Custom Properties for easy theming */\n .webring-nav {\n /* Internal variables that use public API with fallbacks */\n --webring-font-family: var(--webring-theme-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);\n --webring-bg-color: var(--webring-theme-bg);\n --webring-border-color: var(--webring-theme-border);\n --webring-text-color: var(--webring-theme-text);\n --webring-btn-bg: var(--webring-theme-btn-bg);\n --webring-btn-border: var(--webring-theme-btn-border);\n --webring-btn-text: var(--webring-theme-btn-text);\n --webring-btn-hover-bg: var(--webring-theme-btn-hover-bg);\n --webring-btn-hover-text: var(--webring-theme-btn-hover-text);\n }\n\n /* Common theme styles using CSS variables */\n .webring-nav {\n background-color: var(--webring-bg-color);\n }\n .webring-nav[data-widget-type="full"] {\n border: 2.5px solid var(--webring-border-color);\n }\n .webring-nav .webring-title {\n font-weight: 600;\n color: var(--webring-text-color);\n }\n .webring-nav .webring-btn {\n text-wrap: nowrap;\n font-weight: 600;\n color: var(--webring-btn-text);\n background-color: var(--webring-btn-bg);\n border: 2.5px solid var(--webring-btn-border);\n transition: background-color 0.2s ease, color 0.2s ease;\n }\n .webring-nav .webring-btn:focus {\n outline: none;\n background-color: transparent;\n color: var(--webring-btn-text);\n }\n .webring-nav .webring-btn:hover,\n .webring-nav .webring-btn:active {\n background-color: var(--webring-btn-hover-bg);\n color: var(--webring-btn-hover-text);\n }\n .webring-nav svg {\n fill: currentColor;\n }\n\n /* Light theme defaults */\n .webring-nav {\n --webring-theme-bg: #ffffff;\n --webring-theme-border: #000000;\n --webring-theme-text: #000000;\n --webring-theme-btn-bg: #ffffff;\n --webring-theme-btn-border: #000000;\n --webring-theme-btn-text: #000000;\n --webring-theme-btn-hover-bg: #000000;\n --webring-theme-btn-hover-text: #ffffff;\n }\n\n /* Dark theme overrides */\n .webring-nav[data-theme="dark"] {\n --webring-theme-bg: #000000;\n --webring-theme-border: #ffffff;\n --webring-theme-text: #ffffff;\n --webring-theme-btn-bg: #000000;\n --webring-theme-btn-border: #ffffff;\n --webring-theme-btn-text: #ffffff;\n --webring-theme-btn-hover-bg: #ffffff;\n --webring-theme-btn-hover-text: #000000;\n }\n '});let l=!1;n()}();
|
@@ -19,6 +19,7 @@ module Webring
|
|
19
19
|
.read
|
20
20
|
.gsub('"<<REPLACE_ME_LOGO_SVG_FUNCTION>>"', logo_svg_function)
|
21
21
|
.gsub('"<<REPLACE_ME_TEXT_DEFAULTS>>"', JSON.generate(text_defaults))
|
22
|
+
.gsub('"<<REPLACE_ME_WIDGET_FETCH_METRICS_PATH>>"', widget_fetch_metrics_path)
|
22
23
|
|
23
24
|
render js: widget_js
|
24
25
|
end
|
@@ -50,6 +51,10 @@ module Webring
|
|
50
51
|
}
|
51
52
|
end
|
52
53
|
|
54
|
+
def widget_fetch_metrics_path
|
55
|
+
nil # to be overridden in the custom widget controller
|
56
|
+
end
|
57
|
+
|
53
58
|
def set_cors_headers
|
54
59
|
response.headers['Access-Control-Allow-Origin'] = '*'
|
55
60
|
response.headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
|
data/lib/webring/engine.rb
CHANGED
@@ -2,6 +2,11 @@ module Webring
|
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace Webring
|
4
4
|
|
5
|
+
# Add routing helpers to Rails router
|
6
|
+
initializer 'webring.routing' do
|
7
|
+
ActionDispatch::Routing::Mapper.include Webring::Routing
|
8
|
+
end
|
9
|
+
|
5
10
|
# Add concerns to autoload paths
|
6
11
|
initializer 'webring.autoload_paths' do |app|
|
7
12
|
app.config.autoload_paths += %W[#{config.root}/app/models/concerns]
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Webring
|
2
|
+
module Routing
|
3
|
+
def webring_routes(options = {})
|
4
|
+
setup_webring_routes(options)
|
5
|
+
setup_webring_metrics(options)
|
6
|
+
setup_membership_requests(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def setup_webring_routes(options)
|
12
|
+
navigation_controller = options[:navigation] || 'navigation'
|
13
|
+
widget_controller = options[:widget] || 'widget'
|
14
|
+
mount_path = options[:mount_path] || 'webring'
|
15
|
+
mount_as = options[:mount_as] || 'webring'
|
16
|
+
|
17
|
+
# mount Webring::Engine => mount_path, as: mount_as
|
18
|
+
|
19
|
+
scope module: mount_path, as: mount_as do
|
20
|
+
get 'widget.js', to: "#{widget_controller}#show", format: 'js', as: :widget
|
21
|
+
get 'webring/next', to: "#{navigation_controller}#next", as: :next
|
22
|
+
get 'webring/previous', to: "#{navigation_controller}#previous", as: :previous
|
23
|
+
get 'webring/random', to: "#{navigation_controller}#random", as: :random
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup_webring_metrics(options)
|
28
|
+
return if options[:skip_metrics]
|
29
|
+
|
30
|
+
post 'metrics/widget_fetched', to: 'metrics#widget_fetched', as: :widget_fetched_metrics
|
31
|
+
options 'metrics/widget_fetched', to: 'metrics#options_widget_fetched'
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup_membership_requests(options)
|
35
|
+
return if options[:skip_membership_requests]
|
36
|
+
|
37
|
+
namespace :webring do
|
38
|
+
resources :membership_requests, only: %i[new create] do
|
39
|
+
collection do
|
40
|
+
get :thank_you
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/webring/version.rb
CHANGED
data/lib/webring-rails.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webring-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nikita Shkoda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
11
|
+
date: 2025-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -90,7 +90,6 @@ files:
|
|
90
90
|
- app/models/webring/application_record.rb
|
91
91
|
- app/models/webring/member.rb
|
92
92
|
- app/models/webring/membership_request.rb
|
93
|
-
- config/routes.rb
|
94
93
|
- lib/generators/USAGE
|
95
94
|
- lib/generators/webring/custom_widget_controller/custom_widget_controller_generator.rb
|
96
95
|
- lib/generators/webring/custom_widget_controller/templates/custom_widget_controller.rb
|
@@ -112,6 +111,7 @@ files:
|
|
112
111
|
- lib/generators/webring/shared/route_injector.rb
|
113
112
|
- lib/webring-rails.rb
|
114
113
|
- lib/webring/engine.rb
|
114
|
+
- lib/webring/routing.rb
|
115
115
|
- lib/webring/version.rb
|
116
116
|
homepage: https://github.com/cybergizer-hq/webring-rails
|
117
117
|
licenses:
|