根据URL改变皮肤层
我正在创建一个具有“桌面”和“移动”主题的网站。我这个网站有两个主题包:mysite.theme 和 mysite.mobile_theme。 mobile_theme 是桌面主题的精简版本,具有新视图和精简的视图集。我想根据访问网站的 URL(即 mobile.mysite.com 与 www.mysite.com)在这两个主题之间切换。
由于移动和桌面主题将共享大量代码,mysite.mobile_theme 通过以下方式从 mysite.theme 继承:
1)mobile_theme GS Skins.xml 有一个基于旧主题的皮肤路径,因此桌面主题的 CSS 等。使用:
<skin-path name="mysite.mobile_theme" based-on="mysite.theme">
2) IThemeSpecific 标记对原始标记进行子类化,因此我没有覆盖移动网站的视图回退到 mysite.theme 中的视图:
from mysite.theme.browser.interfaces import IThemeSpecific as IBaseTheme
class IThemeSpecific(IBaseTheme):
"""Marker interface that defines a Zope 3 browser layer.
"""
3) 我已在 mysite.mobile_theme 中注册了各种视图,以覆盖中的某些视图我的网站主题。
4)我使用通用设置为每个主题注册不同的视图。
在此阶段,如果我在“默认皮肤”选项门户皮肤 -> 属性中选择 mysite.mobile_theme,一切正常:使用我的视图,并选择 mobile_theme 的 GS 配置文件中的视图设置正确地起来。所以看来主题总体设置正确。
然而,如上所述,我想根据 URL 在这两个主题之间进行交换。
首先,我将“默认皮肤”换回“mysite.theme”。然后,我在 Plone 网站的根目录中创建了一个 access_rule,大致遵循这些说明 根据 URL 选择皮肤。它位于 plonesite/access_rule 并设置为 plone 站点的 access_rule:
url = context.REQUEST.get('ACTUAL_URL', '')
if 'mobile' in url:
context.changeSkin('mysite.mobile_theme', context.REQUEST)
else:
context.changeSkin('mysite.theme', context.REQUEST)
我还尝试使用 context.REQUEST.set('plone_skin', 'mysite.theme')
而不是调用 <代码>context.changeSkin(...)。
使用此设置,显示的视图会根据我使用的 URL 正确更改 - 所以看起来皮肤在某个时刻正在更改 - 但 mysite.mobile_theme 的视图类/模板不会优先于 mysite 使用.主题的。总之:
- 如果我从包含“mobile”的 URL 调用,我会得到 mysite.theme 的视图,但会得到 mysite.mobile_theme 的 viewlet 注册。
- 否则,我会获得 mysite.theme 的视图和 mysite.theme 的 viewlet 注册。
看来我可能必须挂钩遍历机制来更改它,因此如果 URL 中包含“mobile”,则选择针对其 IThemeSpecific 注册的 mysite.mobile_theme 视图,而不是 mysite.theme 视图,但我不确定这是正确的,我也不会这样做。
有人能给我一些指点吗?
最初询问后 3 小时更新
回答我自己的问题(由于 SO 的规则,我不能再过 5 个小时):
“”” 看来您必须在堆栈中的较低位置进行修补才能使此工作正常进行。我查看了 plone.gomobile 是如何完成的,他们对皮肤选择代码本身进行了猴子补丁。请参阅:
I am creating a site which will have a "desktop" and a "mobile" theme. I've two theme packages for this site: mysite.theme and mysite.mobile_theme. The mobile_theme is a stripped down version of the desktop theme, with new views and a reduced set of viewlets. I want to switch between these two themes based on the URL the site is visited from (i.e., mobile.mysite.com vs. www.mysite.com).
As the mobile and desktop themes will share a lot of code, mysite.mobile_theme descends from mysite.theme in the following ways:
1) mobile_theme GS skins.xml has a skin path based on the old theme, so the desktop theme's CSS etc. is used:
<skin-path name="mysite.mobile_theme" based-on="mysite.theme">
2) IThemeSpecific marker subclasses the original one, so views which I'm not overriding for the mobile site fallback to the ones in mysite.theme:
from mysite.theme.browser.interfaces import IThemeSpecific as IBaseTheme
class IThemeSpecific(IBaseTheme):
"""Marker interface that defines a Zope 3 browser layer.
"""
3) I have registered various views in mysite.mobile_theme to override the certain ones in mysite.theme.
4) I've used generic setup to have different viewlet registrations for each theme.
At this stage, if I select mysite.mobile_theme in the "Default skin" option portal skins->properties, everything works correctly: my views are used and the viewlets settings from the mobile_theme's GS profile are picked up correctly. So it appears the theme is set up correctly overall.
As mentioned above, however, I would like to swap between these two themes based on URL.
First, I swapped the "Default skin" back to "mysite.theme". I then created an access_rule in the root on my Plone site, roughly following these instructions to select a skin based on URL. It's at plonesite/access_rule and is set up as the access_rule for the plone site:
url = context.REQUEST.get('ACTUAL_URL', '')
if 'mobile' in url:
context.changeSkin('mysite.mobile_theme', context.REQUEST)
else:
context.changeSkin('mysite.theme', context.REQUEST)
I've also tried using context.REQUEST.set('plone_skin', 'mysite.theme')
rather than calling context.changeSkin(...)
.
Using this setup, the viewlets displayed change correctly based on the URL I've used--so it looks like the skin is being changed at some point--but the mysite.mobile_theme's view classes/templates are not being used in preference to mysite.theme's. In summary:
- If I call from a URL containing "mobile" I get mysite.theme's views, but mysite.mobile_theme's viewlet registrations.
- Otherwise, I get mysite.theme's views and mysite.theme's viewlet registrations.
It looks like I might have to hook into the traversal mechanism to change it so if "mobile" is in the URL, the mysite.mobile_theme's views registered against its IThemeSpecific are chosen rather than the mysite.theme ones, but I'm not sure this is correct nor how I'd go about this.
Can anyone give me some pointers?
UPDATE 3hrs after originally asking
To answer my own question (which I can't do for another 5 hours due to SO's rules):
"""
It would appear that you must patch much lower down in the stack to make this work. I looked at how it was done in plone.gomobile, and they monkeypatch the skin choosing code itself. See:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以使用 collective.editskinswitcher。它的主要用例是在 edit.example.com 上使用 Plone 默认主题,在 www.example.com 上使用我的自定义主题。不过,您可以调整其属性表以适合您的用例。
由于“移动主题”用例相当常见,我会接受补丁以使其更容易;或者我可以找个时间自己研究一下。
(顺便说一句,请注意,当您错过为特定浏览器层注册的某些项目时,有一个修复浏览器层分支可能会有所帮助;似乎已准备好合并,只是我想先添加一些测试。)
You could use collective.editskinswitcher. Its main use case is to use the Plone Default theme on say edit.example.com and My Custom Theme on www.example.com. You can probably tweak its property sheet to fit your use case though.
Since the 'mobile theme' use case is fairly common I would accept patches to make that easier; or I may work on that myself some time.
(BTW, note that there is a fix-browser-layers branch that may help when you miss some items that are registered for a specific browser layer; seems ready to merge except that I would like to add some tests first.)
我已经在一些移动主题原型中做到了这一点。请考虑这两个插件尚未准备好用于生产:
代码为:
skintool 上的补丁告诉皮肤层是这个如果浏览器层: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/SkinsTool.py
如果您使用 plone.app.theming,您还可以切换重氮主题:https://github.com/toutpt/plonetheme.jquerymobile/blob /master/plonetheme/jquerymobile/transform.py
I have done this in some prototypes of mobile themes. Please consider thoses two addons not ready for production:
The related code is:
The patch on skintool to tell skin layer is this one if browser layer: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/SkinsTool.py
If you are using plone.app.theming, you also can switch your diazo theme: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/transform.py
我是否正确理解,在移动 URL 处,您的皮肤是正确的,但您的 Zope3 视图不正确?这对我来说很有意义,因为视图类基于接口。在上面的相同代码中,使用
context.changeSkin
,添加:并让您的视图 zcml 指定
for ... IMobileView
[编辑:再想一想,这确实应该当你改变皮肤时会发生什么 - 额外的界面将是你的“IThemeSpecific” - 所以我不确定这里有什么作用,但尝试
alsoProvides(context, IThemeSpecific)
]Do I understand correctly that at the mobile URL your skins are correct, but your Zope3 Views are not? Which makes sense to me, since the view classes are based on Interfaces. In the same code above, where you use
context.changeSkin
, add:and have your view zcml specify
for ... IMobileView
[edit: on second thoughts, this really should be what happens when you change the skin - where the additional inteface will be your "IThemeSpecific" - so I'm not sure what's at play here, but it wouldn't hurt to try
alsoProvides(context, IThemeSpecific)
]