initial commit; NuPlone, renamed to PcfIntranetStyle
|
@ -0,0 +1 @@
|
||||||
|
#
|
|
@ -0,0 +1,30 @@
|
||||||
|
<configure
|
||||||
|
xmlns="http://namespaces.zope.org/zope"
|
||||||
|
xmlns:browser="http://namespaces.zope.org/browser"
|
||||||
|
xmlns:cmf="http://namespaces.zope.org/cmf"
|
||||||
|
>
|
||||||
|
|
||||||
|
<include file="profiles.zcml" />
|
||||||
|
|
||||||
|
<cmf:registerDirectory
|
||||||
|
name="skins"
|
||||||
|
directory="skins"
|
||||||
|
recursive="True"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<interface
|
||||||
|
interface=".interfaces.IThemeSpecific"
|
||||||
|
type="zope.publisher.interfaces.browser.IBrowserSkinType"
|
||||||
|
name="PcfIntranetStyle"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- The personal bar -->
|
||||||
|
<browser:viewlet
|
||||||
|
name="plone.personal_bar"
|
||||||
|
layer=".interfaces.IThemeSpecific"
|
||||||
|
manager="plone.app.layout.viewlets.interfaces.IPortalHeader"
|
||||||
|
class="plone.app.layout.viewlets.common.PersonalBarViewlet"
|
||||||
|
permission="zope2.View"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</configure>
|
|
@ -0,0 +1,6 @@
|
||||||
|
from plone.theme.interfaces import IDefaultPloneLayer
|
||||||
|
|
||||||
|
class IThemeSpecific(IDefaultPloneLayer):
|
||||||
|
"""Marker interface that defines a Zope 3 skin layer bound to a skin
|
||||||
|
selection in portal_skins.
|
||||||
|
"""
|
|
@ -0,0 +1,15 @@
|
||||||
|
<configure
|
||||||
|
xmlns="http://namespaces.zope.org/zope"
|
||||||
|
xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
|
||||||
|
i18n_domain="pcfintranetstyle">
|
||||||
|
|
||||||
|
<genericsetup:registerProfile
|
||||||
|
name="pcfintranetstyle"
|
||||||
|
title="PcfIntranetStyle"
|
||||||
|
directory="profiles/default"
|
||||||
|
description="Extension profile for PcfIntranetStyle Product."
|
||||||
|
provides="Products.GenericSetup.interfaces.EXTENSION"
|
||||||
|
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</configure>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<object name="portal_css" meta_type="Stylesheets Registry">
|
||||||
|
<stylesheet title="" cacheable="True" compression="safe" cookable="True"
|
||||||
|
enabled="1" expression="" id="pcf-intranet.css" media="screen"
|
||||||
|
rel="stylesheet" rendering="import"/>
|
||||||
|
</object>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<import-steps>
|
||||||
|
<import-step id="pcfintranetstyle_various"
|
||||||
|
version="20070817-01"
|
||||||
|
handler="Products.PcfIntranetStyle.setuphandlers.importVarious"
|
||||||
|
title="PcfIntranetStyle: miscellaneous import steps">
|
||||||
|
<dependency step="skins" />
|
||||||
|
Various import steps that are not handled by GS import/export
|
||||||
|
handlers.
|
||||||
|
</import-step>
|
||||||
|
</import-steps>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<object name="portal_javascripts">
|
||||||
|
|
||||||
|
<javascript cacheable="True" compression="safe" cookable="True" enabled="True"
|
||||||
|
expression="" id="multi-resolution.js" inline="False"
|
||||||
|
insert-after="toc.js"/>
|
||||||
|
|
||||||
|
</object>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<metadata>
|
||||||
|
<version>0.9.3</version>
|
||||||
|
</metadata>
|
|
@ -0,0 +1 @@
|
||||||
|
Need to check for this to ensure setuphandlers don't run when they shouldn't.
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<portlets>
|
||||||
|
<portlet
|
||||||
|
addview="portlets.Language"
|
||||||
|
title="Language"
|
||||||
|
description="A portlet which shows the available languages."
|
||||||
|
/>
|
||||||
|
</portlets>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<object name="portal_skins" default_skin="PcfIntranetStyle">
|
||||||
|
<object name="pcfintranetstyle_scripts"
|
||||||
|
meta_type="Filesystem Directory View"
|
||||||
|
directory="Products.PcfIntranetStyle:skins/pcfintranetstyle_scripts"/>
|
||||||
|
<object name="pcfintranetstyle_images"
|
||||||
|
meta_type="Filesystem Directory View"
|
||||||
|
directory="Products.PcfIntranetStyle:skins/pcfintranetstyle_images"/>
|
||||||
|
<object name="pcfintranetstyle_styles"
|
||||||
|
meta_type="Filesystem Directory View"
|
||||||
|
directory="Products.PcfIntranetStyle:skins/pcfintranetstyle_styles"/>
|
||||||
|
<object name="pcfintranetstyle_templates"
|
||||||
|
meta_type="Filesystem Directory View"
|
||||||
|
directory="Products.PcfIntranetStyle:skins/pcfintranetstyle_templates"/>
|
||||||
|
<skin-path name="PcfIntranetStyle" based-on="Plone Default">
|
||||||
|
<layer name="pcfintranetstyle_styles"
|
||||||
|
insert-after="custom"/>
|
||||||
|
<layer name="pcfintranetstyle_images"
|
||||||
|
insert-after="pcfintranetstyle_styles"/>
|
||||||
|
<layer name="pcfintranetstyle_templates"
|
||||||
|
insert-after="pcfintranetstyle_images"/>
|
||||||
|
<layer name="pcfintranetstyle_scripts"
|
||||||
|
insert-after="pcfintranetstyle_templates"/>
|
||||||
|
</skin-path>
|
||||||
|
</object>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<object>
|
||||||
|
<hidden manager="plone.portaltop" skinname="PcfIntranetStyle">
|
||||||
|
<viewlet name="plone.personal_bar"/>
|
||||||
|
<viewlet name="plone.app.i18n.locales.languageselector" />
|
||||||
|
</hidden>
|
||||||
|
<order manager="plone.portalheader" skinname="PcfIntranetStyle" based-on="Plone Default">
|
||||||
|
<viewlet name="plone.personal_bar" insert-after="plone.site_actions" />
|
||||||
|
</order>
|
||||||
|
</object>
|
|
@ -0,0 +1,39 @@
|
||||||
|
from StringIO import StringIO
|
||||||
|
|
||||||
|
from zope.component import getUtility
|
||||||
|
from zope.component import getMultiAdapter
|
||||||
|
|
||||||
|
from plone.portlets.interfaces import IPortletAssignmentMapping
|
||||||
|
from plone.portlets.interfaces import IPortletManager
|
||||||
|
from plone.app.portlets import portlets
|
||||||
|
|
||||||
|
|
||||||
|
def addSearchPortlet(portal, out):
|
||||||
|
leftColumn = getUtility(IPortletManager, name=u'plone.leftcolumn', context=portal)
|
||||||
|
left = getMultiAdapter((portal, leftColumn,), IPortletAssignmentMapping, context=portal)
|
||||||
|
if u'portlets.Search' not in left:
|
||||||
|
print >> out, "Adding search portlet to the left column"
|
||||||
|
left[u'portlets.Search'] = portlets.search.Assignment()
|
||||||
|
order = [left.keys()[-1]]+left.keys()[:-1]
|
||||||
|
left.updateOrder(list(order))
|
||||||
|
|
||||||
|
def addLanguagePortlet(portal, out):
|
||||||
|
leftColumn = getUtility(IPortletManager, name=u'plone.leftcolumn', context=portal)
|
||||||
|
left = getMultiAdapter((portal, leftColumn,), IPortletAssignmentMapping, context=portal)
|
||||||
|
if u'portlets.Language' not in left:
|
||||||
|
print >> out, "Adding language portlet to the left column"
|
||||||
|
left[u'portlets.Language'] = portlets.language.Assignment()
|
||||||
|
order = [left.keys()[-1]]+left.keys()[:-1]
|
||||||
|
left.updateOrder(list(order))
|
||||||
|
|
||||||
|
|
||||||
|
def importVarious(context):
|
||||||
|
|
||||||
|
if context.readDataFile('pcfintranetstyle_various.txt') is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
site = context.getSite()
|
||||||
|
out = StringIO()
|
||||||
|
|
||||||
|
addSearchPortlet(site, out)
|
||||||
|
addLanguagePortlet(site, out)
|
After Width: | Height: | Size: 55 B |
After Width: | Height: | Size: 55 B |
After Width: | Height: | Size: 43 B |
After Width: | Height: | Size: 42 B |
After Width: | Height: | Size: 46 B |
After Width: | Height: | Size: 46 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 588 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 43 B |
After Width: | Height: | Size: 104 B |
After Width: | Height: | Size: 104 B |
After Width: | Height: | Size: 49 B |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 184 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 556 B |
After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 202 B |
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 631 B |
After Width: | Height: | Size: 227 B |
After Width: | Height: | Size: 228 B |
After Width: | Height: | Size: 330 B |
After Width: | Height: | Size: 227 B |
After Width: | Height: | Size: 228 B |
After Width: | Height: | Size: 333 B |
After Width: | Height: | Size: 134 B |
After Width: | Height: | Size: 135 B |
After Width: | Height: | Size: 154 B |
After Width: | Height: | Size: 136 B |
After Width: | Height: | Size: 135 B |
After Width: | Height: | Size: 153 B |
After Width: | Height: | Size: 333 B |
After Width: | Height: | Size: 62 B |
After Width: | Height: | Size: 64 B |
After Width: | Height: | Size: 62 B |
After Width: | Height: | Size: 59 B |
After Width: | Height: | Size: 61 B |
After Width: | Height: | Size: 59 B |
|
@ -0,0 +1,29 @@
|
||||||
|
registerPloneFunction(function() {
|
||||||
|
var f = function() {
|
||||||
|
var frameWidth;
|
||||||
|
if (self.innerWidth) {
|
||||||
|
frameWidth = self.innerWidth;
|
||||||
|
} else if (document.documentElement && document.documentElement.clientWidth) {
|
||||||
|
frameWidth = document.documentElement.clientWidth;
|
||||||
|
} else if (document.body) {
|
||||||
|
frameWidth = document.body.clientWidth;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (frameWidth < 1014) {
|
||||||
|
addClassName(document.body, 'narrow');
|
||||||
|
removeClassName(document.body, 'medium');
|
||||||
|
removeClassName(document.body, 'wide');
|
||||||
|
} else if (frameWidth > 1260) {
|
||||||
|
removeClassName(document.body, 'narrow');
|
||||||
|
removeClassName(document.body, 'medium');
|
||||||
|
addClassName(document.body, 'wide');
|
||||||
|
} else {
|
||||||
|
removeClassName(document.body, 'narrow');
|
||||||
|
addClassName(document.body, 'medium');
|
||||||
|
removeClassName(document.body, 'wide');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
registerEventListener(window, 'resize', f);
|
||||||
|
f();
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
#portal-column-two dt.portletHeader { height: 1%;}
|
||||||
|
#portal-column-two dt.portletHeader a {position:relative;}
|
||||||
|
#portal-column-two dl.portletCalendar dt a.calendarNext {
|
||||||
|
margin-left:56px;
|
||||||
|
top:-5px;
|
||||||
|
padding-top:30px;
|
||||||
|
}
|
||||||
|
#portal-column-two dl.portletCalendar dt a.calendarPrevious {
|
||||||
|
top:-5px;
|
||||||
|
padding-top:30px;
|
||||||
|
}
|
||||||
|
/* avoid peekaboo bug on the stat pulldown */
|
||||||
|
ul#contentActionMenus li dt a {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#region-content ul.formTabs li a {padding: 0;}
|
||||||
|
#region-content ul.formTabs li.lastFormTab {padding:0px;}
|
||||||
|
#region-content ul.formTabs li.lastFormTab a {padding:0px}
|
||||||
|
#region-content ul.formTabs li.firstFormTab {padding:0px}
|
||||||
|
#region-content ul.formTabs li.firstFormTab a {padding:0px}
|
||||||
|
.livesearchContainer {padding-top:0; margin-top:1em}
|
|
@ -0,0 +1,206 @@
|
||||||
|
body {
|
||||||
|
text-align: right;
|
||||||
|
background: url(body-rtl.gif) repeat-y right 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @group Columns */
|
||||||
|
|
||||||
|
#portal-columns {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @group Column One */
|
||||||
|
|
||||||
|
#portal-column-one {
|
||||||
|
float: right;
|
||||||
|
margin-left: 500px;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* @end */
|
||||||
|
|
||||||
|
/* @group Column Two */
|
||||||
|
|
||||||
|
#portal-column-two {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* @end */
|
||||||
|
|
||||||
|
/* @end */
|
||||||
|
|
||||||
|
#portal-column-content {
|
||||||
|
position: absolute;
|
||||||
|
right: 251px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#portal-header {
|
||||||
|
float: right;
|
||||||
|
background: url(body-rtl.gif) repeat-y right 0;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 0;
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
|
.narrow #portal-header {
|
||||||
|
float: left;
|
||||||
|
background: url(body-rtl.gif) repeat-y right 0;
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.narrow #portal-top {
|
||||||
|
width: 737px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#portal-globalnav {
|
||||||
|
float: left;
|
||||||
|
border-left: none;
|
||||||
|
border-right: 1px solid gray;
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#portal-globalnav li {
|
||||||
|
float: right;
|
||||||
|
border-right: 1px solid #7dabcf;
|
||||||
|
margin-right: -1px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#portal-globalnav li a {
|
||||||
|
min-height: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#portal-column-two dl.portletCalendar dt a.calendarNext {
|
||||||
|
margin-left: 0;
|
||||||
|
position: absolute;
|
||||||
|
left: 7px;
|
||||||
|
right: auto;
|
||||||
|
background: url(buttonBack.png) no-repeat 3px center;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#portal-column-two dl.portletCalendar dt a.calendarPrevious {
|
||||||
|
margin-left: 0;
|
||||||
|
position: absolute;
|
||||||
|
left: 26px;
|
||||||
|
right: auto;
|
||||||
|
|
||||||
|
background: url(buttonForward.png) no-repeat 3px center;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
a#portal-logo {
|
||||||
|
float: right;
|
||||||
|
height: 0;
|
||||||
|
padding-top: 63px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 0;
|
||||||
|
background: url(logo-rtl.gif) no-repeat right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.narrow a#portal-logo {
|
||||||
|
position: absolute;
|
||||||
|
height: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.narrow ul#portal-globalnav {
|
||||||
|
clear: left;
|
||||||
|
width: 434px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#portal-siteactions
|
||||||
|
{
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
float: left;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#portal-personaltools-wrapper {
|
||||||
|
float: left;
|
||||||
|
clear: left;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.narrow #portal-personaltools-wrapper {
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#portal-breadcrumbs {
right: 259px;
|
||||||
|
left: auto;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#portal-breadcrumbs a, #portal-breadcrumbs span span {
|
||||||
|
float: right;
|
||||||
|
padding: 5px 10pt 5px 0;
|
||||||
|
background: url(breadCrumbDivider-rtl.gif) no-repeat right center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#portal-column-one dl {
|
||||||
|
margin: 0 25px 25px 0;
}
|
||||||
|
|
||||||
|
div.managePortletsLink a {
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
padding-right: 20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.searchField {
|
||||||
|
background: url(searchField.png) no-repeat left center;
|
||||||
|
padding: 4px 5px 4px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.portletNavigationTree {
|
||||||
|
margin-left: auto !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.portletNavigationTree dd a {
|
||||||
|
padding-right: 25px;
|
||||||
|
padding-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.portletNavigationTree li ul {
|
||||||
|
margin-left: auto;
|
||||||
|
padding-left: 0;
|
||||||
|
border-left: none;
|
||||||
|
border-right: 1px solid #666;
|
||||||
|
padding-right: 0;
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.portletNavigationTree li a img {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: -19px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.portletNavigationTree li a {
|
||||||
|
background: url(edgeColour.gif) repeat-y left;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.portletNavigationTree li a.navTreeCurrentItem {
|
||||||
|
background: url(currentNav-rtl.gif) no-repeat left center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.narrow dl.portletCalendar table {
left:-8px;
position:relative;
width: 194px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.narrow dl.portletCalendar table th {
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
body.kupu {
|
||||||
|
padding: 1em 1em 2em 1em !important;
|
||||||
|
background: &dtml-backgroundColor;;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.kupu ol {
|
||||||
|
list-style-type: decimal;
|
||||||
|
margin-left: 2em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.kupu ul {
|
||||||
|
line-height: 1.5em;
|
||||||
|
list-style-type: disc;
|
||||||
|
list-style-image: none;
|
||||||
|
margin: 0.5em 0 0 1.5em!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.kupu li {
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
display: list-item;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
display: list-item!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.kupu blockquote {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
margin-left: 0;
|
||||||
|
border-left: 4px solid &dtml-globalBorderColor;;
|
||||||
|
color: &dtml-discreetColor;;
|
||||||
|
}
|
||||||
|
body.kupu code, tt {
|
||||||
|
font-family: Monaco, "Courier New", Courier, monospace;
|
||||||
|
font-size: 120%;
|
||||||
|
color: &dtml-fontColor;;
|
||||||
|
background-color: &dtml-globalBackgroundColor;;
|
||||||
|
padding: 0 0.1em;
|
||||||
|
}
|
||||||
|
body.kupu pre {
|
||||||
|
font-family: Monaco, "Courier New", Courier, monospace;
|
||||||
|
font-size: 100%;
|
||||||
|
padding: 1em;
|
||||||
|
border: &dtml-borderWidth; &dtml-borderStyle; &dtml-globalBorderColor;;
|
||||||
|
color: &dtml-fontColor;;
|
||||||
|
background-color: &dtml-globalBackgroundColor;;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
title:string=PcfIntranetStyle's color, font, logo and border defaults
|
||||||
|
|
||||||
|
plone_skin:string=PcfIntranetStyle
|
||||||
|
|
||||||
|
logoName:string=logo.gif
|
||||||
|
|
||||||
|
fontFamily:string="Helvetica Neue", Arial, sans-serif
|
||||||
|
fontBaseSize:string=100%
|
||||||
|
fontColor:string=Black
|
||||||
|
fontSmallSize:string=85%
|
||||||
|
|
||||||
|
backgroundColor:string=White
|
||||||
|
|
||||||
|
linkColor:string=#436976
|
||||||
|
linkActiveColor:string=Red
|
||||||
|
linkVisitedColor:string=Purple
|
||||||
|
|
||||||
|
borderWidth:string=1px
|
||||||
|
borderStyle:string=solid
|
||||||
|
borderStyleAnnotations:string=dashed
|
||||||
|
|
||||||
|
globalBorderColor:string=#8cacbb
|
||||||
|
globalBackgroundColor:string=#dee7ec
|
||||||
|
globalFontColor:string=#436976
|
||||||
|
|
||||||
|
headingFontFamily:string="Times New Roman", Times, Georgia, serif
|
||||||
|
|
||||||
|
contentViewBorderColor:string=#74ae0b
|
||||||
|
contentViewBackgroundColor:string=#cde2a7
|
||||||
|
contentViewFontColor:string=#578308
|
||||||
|
|
||||||
|
inputFontColor:string=Black
|
||||||
|
|
||||||
|
textTransform:string=lowercase
|
||||||
|
|
||||||
|
evenRowBackgroundColor:string=#eef3f5
|
||||||
|
oddRowBackgroundColor:string=transparent
|
||||||
|
|
||||||
|
notifyBorderColor:string=#ffa500
|
||||||
|
notifyBackgroundColor:string=#ffce7b
|
||||||
|
|
||||||
|
discreetColor:string=#76797c
|
||||||
|
helpBackgroundColor:string=#ffffe1
|
||||||
|
|
||||||
|
portalMinWidth:string=70em
|
||||||
|
columnOneWidth:string=16em
|
||||||
|
columnTwoWidth:string=16em
|
|
@ -0,0 +1,18 @@
|
||||||
|
a.state-private {
|
||||||
|
color: #ff7664 !important;
|
||||||
|
}
|
||||||
|
a.state-visible {
|
||||||
|
color: #a3e63d !important;
|
||||||
|
}
|
||||||
|
a.state-published {
|
||||||
|
color: #7dabcf; !important;
|
||||||
|
}
|
||||||
|
a.state-pending {
|
||||||
|
color: orange !important;
|
||||||
|
}
|
||||||
|
a.state-expired {
|
||||||
|
color: silver !important;
|
||||||
|
}
|
||||||
|
a.syndicated {
|
||||||
|
color: #008000 !important;
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
## Script (Python) "livescript_reply"
|
||||||
|
##bind container=container
|
||||||
|
##bind context=context
|
||||||
|
##bind namespace=
|
||||||
|
##bind script=script
|
||||||
|
##bind subpath=traverse_subpath
|
||||||
|
##parameters=q,limit=10,path=None
|
||||||
|
##title=Determine whether to show an id in an edit form
|
||||||
|
|
||||||
|
from Products.CMFCore.utils import getToolByName
|
||||||
|
from Products.CMFPlone import PloneMessageFactory as _
|
||||||
|
from Products.CMFPlone.browser.navtree import getNavigationRoot
|
||||||
|
from Products.CMFPlone.utils import safe_unicode
|
||||||
|
from Products.PythonScripts.standard import url_quote
|
||||||
|
from Products.PythonScripts.standard import url_quote_plus
|
||||||
|
|
||||||
|
ploneUtils = getToolByName(context, 'plone_utils')
|
||||||
|
portal_url = getToolByName(context, 'portal_url')()
|
||||||
|
pretty_title_or_id = ploneUtils.pretty_title_or_id
|
||||||
|
plone_view = context.restrictedTraverse('@@plone')
|
||||||
|
|
||||||
|
portalProperties = getToolByName(context, 'portal_properties')
|
||||||
|
siteProperties = getattr(portalProperties, 'site_properties', None)
|
||||||
|
useViewAction = []
|
||||||
|
if siteProperties is not None:
|
||||||
|
useViewAction = siteProperties.getProperty('typesUseViewActionInListings', [])
|
||||||
|
|
||||||
|
# SIMPLE CONFIGURATION
|
||||||
|
USE_ICON = True
|
||||||
|
USE_RANKING = False
|
||||||
|
MAX_TITLE = 29
|
||||||
|
MAX_DESCRIPTION = 93
|
||||||
|
|
||||||
|
# generate a result set for the query
|
||||||
|
catalog = context.portal_catalog
|
||||||
|
|
||||||
|
friendly_types = ploneUtils.getUserFriendlyTypes()
|
||||||
|
|
||||||
|
def quotestring(s):
|
||||||
|
return '"%s"' % s
|
||||||
|
|
||||||
|
def quote_bad_chars(s):
|
||||||
|
bad_chars = ["(", ")"]
|
||||||
|
for char in bad_chars:
|
||||||
|
s = s.replace(char, quotestring(char))
|
||||||
|
return s
|
||||||
|
|
||||||
|
# for now we just do a full search to prove a point, this is not the
|
||||||
|
# way to do this in the future, we'd use a in-memory probability based
|
||||||
|
# result set.
|
||||||
|
# convert queries to zctextindex
|
||||||
|
|
||||||
|
# XXX really if it contains + * ? or -
|
||||||
|
# it will not be right since the catalog ignores all non-word
|
||||||
|
# characters equally like
|
||||||
|
# so we don't even attept to make that right.
|
||||||
|
# But we strip these and these so that the catalog does
|
||||||
|
# not interpret them as metachars
|
||||||
|
##q = re.compile(r'[\*\?\-\+]+').sub(' ', q)
|
||||||
|
for char in '?-+*':
|
||||||
|
q = q.replace(char, ' ')
|
||||||
|
r=q.split()
|
||||||
|
r = " AND ".join(r)
|
||||||
|
r = quote_bad_chars(r)+'*'
|
||||||
|
searchterms = url_quote_plus(r)
|
||||||
|
|
||||||
|
site_encoding = context.plone_utils.getSiteEncoding()
|
||||||
|
if path is None:
|
||||||
|
path = getNavigationRoot(context)
|
||||||
|
results = catalog(SearchableText=r, portal_type=friendly_types, path=path)
|
||||||
|
|
||||||
|
searchterm_query = '?searchterm=%s'%url_quote_plus(q)
|
||||||
|
|
||||||
|
RESPONSE = context.REQUEST.RESPONSE
|
||||||
|
RESPONSE.setHeader('Content-Type', 'text/xml;charset=%s' % site_encoding)
|
||||||
|
|
||||||
|
# replace named entities with their numbered counterparts, in the xml the named ones are not correct
|
||||||
|
# ↓ --> ↓
|
||||||
|
# … --> …
|
||||||
|
legend_livesearch = _('legend_livesearch', default='LiveSearch ↓')
|
||||||
|
label_no_results_found = _('label_no_results_found', default='No matching results found.')
|
||||||
|
label_advanced_search = _('label_advanced_search', default='Advanced Search…')
|
||||||
|
label_show_all = _('label_show_all', default='Show all…')
|
||||||
|
heading_search_results = _('heading_search_results', default='Search results…')
|
||||||
|
|
||||||
|
ts = getToolByName(context, 'translation_service')
|
||||||
|
|
||||||
|
output = []
|
||||||
|
|
||||||
|
def write(s):
|
||||||
|
output.append(safe_unicode(s))
|
||||||
|
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
write('''<h4>%s</h4>''' % ts.translate(heading_search_results))
|
||||||
|
write('''<ul>''')
|
||||||
|
write('''<li>%s</li>''' % ts.translate(label_no_results_found))
|
||||||
|
write('<li><a href="search_form" style="font-weight:normal">%s</a></li>' % ts.translate(label_advanced_search))
|
||||||
|
write('''</ul>''')
|
||||||
|
else:
|
||||||
|
write('''<h4>%s</h4>''' % ts.translate(heading_search_results))
|
||||||
|
write('''<ul>''')
|
||||||
|
for result in results[:limit]:
|
||||||
|
|
||||||
|
icon = plone_view.getIcon(result)
|
||||||
|
itemUrl = result.getURL()
|
||||||
|
if result.portal_type in useViewAction:
|
||||||
|
itemUrl += '/view'
|
||||||
|
itemUrl = itemUrl + searchterm_query
|
||||||
|
|
||||||
|
write('''<li>''')
|
||||||
|
|
||||||
|
full_title = safe_unicode(pretty_title_or_id(result))
|
||||||
|
if len(full_title) > MAX_TITLE:
|
||||||
|
display_title = ''.join((full_title[:MAX_TITLE],'...'))
|
||||||
|
else:
|
||||||
|
display_title = full_title
|
||||||
|
full_title = full_title.replace('"', '"')
|
||||||
|
write('''<a href="%s" title="%s">''' % (itemUrl, full_title))
|
||||||
|
if icon.url is not None and icon.description is not None:
|
||||||
|
write('''<img src="%s" alt="%s" width="%i" height="%i" />''' % (icon.url,
|
||||||
|
icon.description,
|
||||||
|
icon.width,
|
||||||
|
icon.height))
|
||||||
|
|
||||||
|
write('''<span class="livesearchResult-title">%s</span>''' % display_title)
|
||||||
|
write('''<span class="livesearchResult-score">[%s%%]</span>''' % result.data_record_normalized_score_)
|
||||||
|
display_description = safe_unicode(result.Description)
|
||||||
|
if len(display_description) > MAX_DESCRIPTION:
|
||||||
|
display_description = ''.join((display_description[:MAX_DESCRIPTION],'...'))
|
||||||
|
|
||||||
|
if display_description:
|
||||||
|
write('''<span class="livesearchResult-description">%s</span>''' % (display_description))
|
||||||
|
write('''</a>''')
|
||||||
|
write('''</li>''')
|
||||||
|
full_title, display_title, display_description = None, None, None
|
||||||
|
|
||||||
|
if len(results)>limit:
|
||||||
|
# add a more... row
|
||||||
|
write('''<li class="livesearchShowAll">''')
|
||||||
|
write('''<a href="%s">%s</a>''' % ('search?SearchableText=' + searchterms, ts.translate(label_show_all)))
|
||||||
|
write('''</li>''')
|
||||||
|
|
||||||
|
write('''</ul>''')
|
||||||
|
|
||||||
|
return '\n'.join(output).encode(site_encoding)
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
<metal:page define-macro="master"><metal:doctype define-slot="doctype"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"></metal:doctype>
|
||||||
|
<metal:block define-slot="top_slot" />
|
||||||
|
<metal:block use-macro="here/global_defines/macros/defines" />
|
||||||
|
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xml:lang="en"
|
||||||
|
lang="en"
|
||||||
|
tal:define="lang language"
|
||||||
|
tal:attributes="lang lang;
|
||||||
|
xml:lang lang">
|
||||||
|
|
||||||
|
<tal:cache tal:define="charset site_properties/default_charset|string:utf-8">
|
||||||
|
<metal:cache use-macro="here/global_cache_settings/macros/cacheheaders">
|
||||||
|
Get the global cache headers located in global_cache_settings.
|
||||||
|
</metal:cache>
|
||||||
|
</tal:cache>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"
|
||||||
|
tal:define="charset site_properties/default_charset|string:utf-8"
|
||||||
|
tal:attributes="content string:text/html;;charset=${charset}" />
|
||||||
|
|
||||||
|
<metal:baseslot define-slot="base">
|
||||||
|
<base tal:attributes="href here/renderBase" /><!--[if lt IE 7]></base><![endif]-->
|
||||||
|
</metal:baseslot>
|
||||||
|
|
||||||
|
<meta name="generator" content="Plone - http://plone.org" />
|
||||||
|
|
||||||
|
<div tal:replace="structure provider:plone.htmlhead" />
|
||||||
|
|
||||||
|
<meta tal:define="metatags python:putils.listMetaTags(here).items()"
|
||||||
|
tal:condition="metatags"
|
||||||
|
tal:repeat="keyval metatags"
|
||||||
|
tal:attributes="name python:keyval[0];
|
||||||
|
content python:keyval[1];" />
|
||||||
|
|
||||||
|
<!-- Internet Explorer CSS Fixes -->
|
||||||
|
<tal:iefixstart replace="structure string:<!--[if IE]>" />
|
||||||
|
<style type="text/css" media="all" tal:condition="exists: portal/IEFixes.css"
|
||||||
|
tal:content="string:@import url($portal_url/IEFixes.css);">
|
||||||
|
</style>
|
||||||
|
<tal:iefixend replace="structure string:<![endif]-->" />
|
||||||
|
|
||||||
|
<link tal:replace="structure provider:plone.htmlhead.links" />
|
||||||
|
|
||||||
|
<link rel="alternate" href="" title="RSS 1.0" type="application/rss+xml"
|
||||||
|
tal:condition="python: syntool.isSyndicationAllowed(here)"
|
||||||
|
tal:attributes="href string:$here_url/RSS" />
|
||||||
|
|
||||||
|
<!-- Disable IE6 image toolbar -->
|
||||||
|
<meta http-equiv="imagetoolbar" content="no" />
|
||||||
|
|
||||||
|
<tal:comment replace="nothing"> A slot where you can insert elements in the header from a template </tal:comment>
|
||||||
|
<metal:headslot define-slot="head_slot" />
|
||||||
|
|
||||||
|
<tal:comment replace="nothing"> A slot where you can insert CSS in the header from a template </tal:comment>
|
||||||
|
<metal:styleslot define-slot="style_slot" />
|
||||||
|
|
||||||
|
<tal:comment replace="nothing"> This is deprecated, please use style_slot instead. </tal:comment>
|
||||||
|
<metal:cssslot define-slot="css_slot" />
|
||||||
|
|
||||||
|
<tal:comment replace="nothing"> A slot where you can insert javascript in the header from a template </tal:comment>
|
||||||
|
<metal:javascriptslot define-slot="javascript_head_slot" />
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body tal:attributes="class string:${here/getSectionFromURL} template-${template/id};
|
||||||
|
dir python:test(isRTL, 'rtl', 'ltr')">
|
||||||
|
<div id="visual-portal-wrapper">
|
||||||
|
|
||||||
|
<div id="portal-top" i18n:domain="plone">
|
||||||
|
<div tal:replace="structure provider:plone.portaltop" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="visualClear" id="clear-space-before-wrapper-table"><!-- --></div>
|
||||||
|
|
||||||
|
<div id="portal-columns">
|
||||||
|
|
||||||
|
|
||||||
|
<tal:comment replace="nothing"> Start of the left column </tal:comment>
|
||||||
|
<div id="portal-column-one"
|
||||||
|
metal:define-slot="column_one_slot"
|
||||||
|
tal:condition="sl">
|
||||||
|
<div class="visualPadding">
|
||||||
|
<metal:portlets define-slot="portlets_one_slot">
|
||||||
|
<tal:block replace="structure provider:plone.leftcolumn" />
|
||||||
|
</metal:portlets>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<tal:comment replace="nothing"> End of the left column </tal:comment>
|
||||||
|
|
||||||
|
<tal:comment replace="nothing"> Start of main content block </tal:comment>
|
||||||
|
<div id="portal-column-content"
|
||||||
|
tal:define="tabindex python:Iterator(mainSlot=False)">
|
||||||
|
|
||||||
|
<metal:block define-slot="content">
|
||||||
|
<div metal:define-macro="content"
|
||||||
|
tal:define="show_border context/@@plone/showEditableBorder"
|
||||||
|
tal:attributes="class python:test(show_border,'documentEditable','')">
|
||||||
|
|
||||||
|
<div tal:replace="structure provider:plone.contentviews" />
|
||||||
|
|
||||||
|
<div id="region-content"
|
||||||
|
class="documentContent">
|
||||||
|
|
||||||
|
<span id="contentTopLeft"></span>
|
||||||
|
<span id="contentTopRight"></span>
|
||||||
|
|
||||||
|
<a name="documentContent"></a>
|
||||||
|
|
||||||
|
<div metal:use-macro="here/global_statusmessage/macros/portal_message">
|
||||||
|
Portal status message
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="viewlet-above-content" tal:content="structure provider:plone.abovecontent" />
|
||||||
|
|
||||||
|
<metal:slot metal:define-slot="body">
|
||||||
|
<tal:comment replace="nothing">
|
||||||
|
The div with ID #content will only show up if we're actually on a content
|
||||||
|
view, never on edit forms, control panels etc. It's meant to only wrap the
|
||||||
|
actual content that gets rendered on a page, not the other UI elements.
|
||||||
|
</tal:comment>
|
||||||
|
<div id="content"
|
||||||
|
tal:omit-tag="not:context/@@plone_context_state/is_view_template">
|
||||||
|
<metal:header metal:define-slot="header" tal:content="nothing">
|
||||||
|
Visual Header
|
||||||
|
</metal:header>
|
||||||
|
<metal:bodytext metal:define-slot="main" tal:content="nothing">
|
||||||
|
Page body text
|
||||||
|
</metal:bodytext>
|
||||||
|
</div>
|
||||||
|
</metal:slot>
|
||||||
|
|
||||||
|
<metal:sub metal:define-slot="sub">
|
||||||
|
|
||||||
|
<div tal:replace="structure provider:plone.belowcontent" />
|
||||||
|
|
||||||
|
</metal:sub>
|
||||||
|
|
||||||
|
<span id="contentBottomLeft"></span>
|
||||||
|
<span id="contentBottomRight"></span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</metal:block>
|
||||||
|
</div>
|
||||||
|
<tal:comment replace="nothing"> End of main content block </tal:comment>
|
||||||
|
|
||||||
|
<tal:comment replace="nothing"> Start of right column </tal:comment>
|
||||||
|
<div id="portal-column-two"
|
||||||
|
metal:define-slot="column_two_slot"
|
||||||
|
tal:condition="sr">
|
||||||
|
<div class="visualPadding">
|
||||||
|
<metal:portlets define-slot="portlets_two_slot">
|
||||||
|
<tal:block replace="structure provider:plone.rightcolumn" />
|
||||||
|
</metal:portlets>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<tal:comment replace="nothing"> End of the right column </tal:comment>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<tal:comment replace="nothing"> end column wrapper </tal:comment>
|
||||||
|
|
||||||
|
<div class="visualClear" id="clear-space-before-footer"><!-- --></div>
|
||||||
|
|
||||||
|
<div tal:define="context_state context/@@plone_context_state;
|
||||||
|
portlet_assignable context_state/portlet_assignable"
|
||||||
|
tal:condition="python:not sl and not sr and portlet_assignable and checkPermission('Portlets: Manage portlets', context)">
|
||||||
|
<a class="managePortletsFallback"
|
||||||
|
tal:attributes="href string:${context_state/canonical_object_url}/@@manage-portlets"
|
||||||
|
i18n:translate="manage_portlets_fallback">
|
||||||
|
Manage portlets
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<metal:block i18n:domain="plone">
|
||||||
|
|
||||||
|
<div tal:replace="structure provider:plone.portalfooter" />
|
||||||
|
|
||||||
|
</metal:block>
|
||||||
|
|
||||||
|
<div class="visualClear"><!-- --></div>
|
||||||
|
</div>
|
||||||
|
<div id="kss-spinner"><img tal:attributes="src string:${portal_url}/spinner.gif" alt="" /></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</metal:page>
|
|
@ -0,0 +1,59 @@
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
|
||||||
|
xmlns:tal="http://xml.zope.org/namespaces/tal"
|
||||||
|
xmlns:metal="http://xml.zope.org/namespaces/metal"
|
||||||
|
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
|
||||||
|
i18n:domain="plone">
|
||||||
|
<body>
|
||||||
|
<metal:portlet define-macro="portlet"
|
||||||
|
tal:define="controlPanel python:modules['Products.CMFCore.utils'].getToolByName(here, 'portal_controlpanel');
|
||||||
|
groups python:controlPanel.getGroups('site');
|
||||||
|
getIconFor nocall:putils/getIconFor">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="visualPadding">
|
||||||
|
|
||||||
|
<dl class="portlet"
|
||||||
|
id="portlet-prefs">
|
||||||
|
<dt class="portletHeader">
|
||||||
|
<span class="portletTopLeft"></span>
|
||||||
|
<a href=""
|
||||||
|
tal:attributes="href string:${portal_url}/plone_control_panel"
|
||||||
|
i18n:translate="heading_control_panel">Site Setup</a>
|
||||||
|
<span class="portletTopRight"></span>
|
||||||
|
</dt>
|
||||||
|
|
||||||
|
<dd class="portletItem"
|
||||||
|
tal:repeat="group groups">
|
||||||
|
|
||||||
|
<tal:block tal:define="configlets python:controlPanel.enumConfiglets(group=group['id'])"
|
||||||
|
tal:condition="configlets">
|
||||||
|
<strong tal:content="group/title"
|
||||||
|
i18n:translate="">Plone Configlet Group Title</strong>
|
||||||
|
<ul class="configlets">
|
||||||
|
|
||||||
|
<li tal:repeat="configlet configlets">
|
||||||
|
<a href=""
|
||||||
|
tal:attributes="href configlet/url"
|
||||||
|
tal:condition="configlet/visible">
|
||||||
|
<img src="" alt="" tal:attributes="src python:'%s/%s' % (portal_url, getIconFor('controlpanel',configlet['id']));
|
||||||
|
alt configlet/description"
|
||||||
|
i18n:attributes="alt"
|
||||||
|
tal:on-error="string:" />
|
||||||
|
<tal:configletname tal:content="configlet/title"
|
||||||
|
i18n:translate=""></tal:configletname>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</tal:block>
|
||||||
|
<span class="portletBottomLeft"></span>
|
||||||
|
<span class="portletBottomRight"></span>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</metal:portlet>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<metal:page define-macro="master">
|
||||||
|
<tal:block metal:use-macro="here/main_template/macros/master">
|
||||||
|
|
||||||
|
<metal:block fill-slot="top_slot"
|
||||||
|
tal:define="dummy python:request.set('disable_border',1)" />
|
||||||
|
|
||||||
|
<metal:override fill-slot="column_one_slot">
|
||||||
|
<metal:override define-slot="column_one_slot">
|
||||||
|
<div id="portal-column-one">
|
||||||
|
<metal:prefs use-macro="here/portlet_prefs/macros/portlet" />
|
||||||
|
</div>
|
||||||
|
</metal:override>
|
||||||
|
</metal:override>
|
||||||
|
|
||||||
|
<metal:override fill-slot="column_two_slot" />
|
||||||
|
|
||||||
|
<metal:override fill-slot="content">
|
||||||
|
<metal:slot define-slot="prefs_configlet_content">
|
||||||
|
<metal:block metal:use-macro="here/main_template/macros/content">
|
||||||
|
<metal:override metal:fill-slot="main">
|
||||||
|
<metal:slot metal:define-slot="prefs_configlet_main" tal:content="nothing">
|
||||||
|
Page body text
|
||||||
|
</metal:slot>
|
||||||
|
</metal:override>
|
||||||
|
</metal:block>
|
||||||
|
</metal:slot>
|
||||||
|
</metal:override>
|
||||||
|
|
||||||
|
</tal:block>
|
||||||
|
</metal:page>
|
|
@ -0,0 +1 @@
|
||||||
|
trunk
|