Personal tools
You are here: Home Weblog Archive 2007 February

Entries For: February 2007

2007-02-28

A Zope 3 AJAX viewlet manager

Filed Under:

I've finally got tired of writing small fragments of JavaScript code and views to be able to make different areas updatable through ajax for my current Zope 3 application. Plus, when I've started writing this application, I've started doing the layout with viewlets and managers, and it seems that for each viewlet that I'm creating I have to have a way to get its content through AJAX, which means having a page available for it, and this is very odd, as it almost defeats the point of having viewlets.

So I've decided to create the "Ajax viewlet manager". I'm not sure how good of an idea this is, I'll have to give it some thought and see how I feel about it in the future. Let me describe my solution.

First, I want to be able to have the manager available at a certain URL, to be able to reload this URL through an Ajax call later on. So I've created a new namespace traverser, ++vmanager++. A viewlet manager would be accessible (as rendered HTML) at a location such as http://localhost:8080/mysite/myobject/++vmanager++ITop. This is the traverser code:

from zope.publisher.interfaces.browser import IBrowserView
from zope.traversing.interfaces import TraversalError
from zope import component
from zope.interface import implements
from zope.traversing.namespace import SimpleHandler
from zope.viewlet.interfaces import IViewletManager

class vmanager(SimpleHandler):
implements(IBrowserView)
def __init__(self, context, request):
self.context = context
self.request = request

def traverse(self, name, ignored):
manager = component.queryMultiAdapter((self.context, self.request, self), IViewletManager, name=name)
if manager:
return manager
else:
raise TraversalError(self.context, name)

The traverser is registered like this:

<adapter
name="vmanager" for="*"
provides="zope.traversing.interfaces.ITraversable"
factory=".namespace.vmanager"
/>

<view
name="vmanager" for="*"
type="zope.interface.Interface"
provides="zope.traversing.interfaces.ITraversable"
factory=".namespace.vmanager"
/>

The traverse() in the vmanager class will return the manager. One thing to note is that once the manager returned, Zope will try to get the default view for this object, so a default page (index.html) is needed for IViewletManager

class ViewViewletManager(object):
"""View a rendered viewlet manager"""

def __call__(self):
manager = self.context
manager.update()
return manager.render()

This page is registered as

<browser:page
name="index.html"
class=".browser.ViewViewletManager"
for="zope.viewlet.interfaces.IViewletManager"
permission="zope.View"
/>

Next, to automate things a bit more, I wrote a template, along these lines:

<tal:vars
    tal:define="vmgr_name view/__name__; here_url context/@@absolute_url">
    <div id="provider_ITop"
        tal:attributes="id string:provider_$vmgr_name">
        <div tal:repeat="viewlet view/viewlets" tal:omit-tag="">
            <div tal:replace="structure viewlet/render" />
        </div>
    </div>
    <script
        tal:content="string:
function reload_${vmgr_name}(){
    new Ajax.Updater('provider_${vmgr_name}', '$here_url/++vmanager++${vmgr_name}')
}" />
</tal:vars>

This template inserts the viewlet contents in a named container and creates a JavaScript function (which uses Prototype) that can be called later to update that container. The last piece is to tell my viewlet providers to use this template (observe the template argument):

<viewletManager name="IFooter" provides=".IFooterSlotManager"
        class="z3c.viewlet.manager.WeightOrderedViewletManager"
        template="vmanager.pt"
        permission="zope.View" />

I'll probably still have to write some views and JavaScript to make things dynamics, but this solution will sure help to reduce the amount of code I have to write.

2007-02-27

I hate brackets! (or rants of a JavaScript novice programmer)

Filed Under:

Javascript is nice, I'm having fun building this Zope3/Ajax based application that I'm working on right now. What I don't enjoy is the forest of non-alphanumeric characters that has started to clog my code. I'm really a novice when it comes to Javascript, most of my professional programming has been done with other languages, but look for example at this fragment of code:

    for (i=0; i< parent.childNodes.length; i++) {
        el = parent.childNodes.item(i)
        if(el.nodeType == Node.ELEMENT_NODE) {
            if (el.classNames().find(function(s){return s == 'ajax_response'}))
            {
                parent.removeChild(parent.childNodes.item(i));
            }
        }
    }

It's a simple snippet that checks if there's already an "ajax_response" container in the parent container.  On line 4 I've stretched the code as much as I could, already reaching 80 characters (I'm using Prototype, the reasons there's an anonymous function as parameter to the find(), applied on an Enumerator object). The code is ugly and hard to read and comprehend. I'm really beginning to appreciate Python, a python version would have been something like this (trying not to differ too much from the JS version):

for i in range(parent.childNodes.length()):
    el = parent.childNodes[i]
    if el.nodeType is Node.ELEMENT_NODE) and \
         'ajax_response' in el.classNames():
                parent.removeChild(parent.childNodes.item(i))

The block of code have been reduced to almost half the number of lines and I dare say that now it is really possible to read an understand this snippet. Probably the JS code could be improved as well, but I'll keep such optimizations for later on, when my Js-Foo gets better.

Updated (again)

I wrote a Prototype extension to create a "scrollable area". I've modeled the code after the Control.Tabs extension. The control is almost ready. I feel good after understanding JS's OOP system and the Prototype extensions, its bind/bindAsEventListener quirks, but the code remains the same unreadable mess, when compared to Python code.

sizeToNumber = function(size){
//converts a style size (ex: 10px) to a number. Hackish method
return size.substring(0, size.length -2) * 1
}

if(typeof(Control) == "undefined")
var Control = {};
Control.Scroller = Class.create();
Object.extend(Control.Scroller.prototype, {
container:false,
initialize:function(area, options){

// set the options
this.options = $H({
timeslice:0.1,
amount:5,
type:'vertical',
width:'500px',
height:'400px'
}).merge(options || {});
this.area = $(area);
this.sid = 'scroller' + this.area.id;
// insert the control structures
new Insertion.After(this.area,
"<div class='scroller " + this.options.type + "' id='" + this.sid + "'>" +
"<div class='sb b_A' id='" + this.sid + "sb'></div>" +
"<div class='s_outer'>" +
"<div class='s_inner'></div>" +
"</div>" +
"<div class='sb b_B' id='" + this.sid + "sr'></div>" +
"</div>"
);

// div scroller <- container for the entire control
// div sb b_A <- scroll button. b_A = button A, b_B = button B
// div s_outer <- The restricted visible portion of the scrolled content. Has overflow:hidden
// div s_inner <- Container which holds the actual content

inner = $(this.sid).down('.s_inner');
outer = $(this.sid).down('.s_outer');

inner.appendChild(this.area);
outer.style.overflow = 'hidden';
// TODO: only apply one of height/weight

switch (this.options.type) {
case 'vertical':
this.direction = 'marginTop';
outer.style.height = this.options.height;
inner.style.height = this.area.clientHeight + 'px';
break
case 'horizontal':
this.direction = 'marginLeft';
outer.style.width = this.options.width;
inner.style.width = this.area.clientWidth + 'px';
break
default:
throw ("Unsported orientation/style type")
}

//event handlers LEFT (or TOP) scroll button
$(this.sid).down('.b_A').observe('mousedown', function(event){
this.flag=true;
new PeriodicalExecuter(function(pe){
if (this.flag) {
this.doScroll(this.options.amount);
} else {
pe.stop();
}
}.bind(this), this.options.timeslice);
}.bindAsEventListener(this));
$(this.sid).down('.b_A').observe('mouseup', function(event){
this.flag = false;
}.bindAsEventListener(this));

//event handlers RIGHT (or BOTTOM) scroll button
$(this.sid).down('.b_B').observe('mousedown', function(event){
this.flag=true;
new PeriodicalExecuter(function(pe){
if (this.flag) {
inner = $(this.sid).down('.s_inner');
cl_height = sizeToNumber(this.options.height); // the scroller control area
delta = sizeToNumber(inner.style[this.direction]); // how much the inner div was scrolled
if (this.options.type == 'horizontal') {
direction = 'clientWidth'
} else if (this.options.type == 'vertical'){
direction = 'clientHeight'
}
re_size = this.area[direction]; // the real content size (the ideal size)
if (!(((delta * -1) + cl_height) >= re_size)) {
this.doScroll(this.options.amount * -1);
}
} else {
pe.stop();
}
}.bind(this), this.options.timeslice);
}.bindAsEventListener(this));
$(this.sid).down('.b_B').observe('mouseup', function(event){
this.flag = false;
}.bindAsEventListener(this));
},

doScroll:function(amount){
// do a scroll in the direction specified
delta = $(this.sid).down('.s_inner').style[this.direction];
if (!delta) {
delta = "0px";
}
numeric_delta = sizeToNumber(delta) + amount;
if ( numeric_delta > 0) {return}
delta = numeric_delta + "px";
$(this.sid).down('.s_inner').style[this.direction] = delta;
},

scrollToElement:function(target_id){
// scroll to a specified id element inside the area

switch (this.options.type) {
case 'vertical':
offsetType = 'offsetTop';
break;
case 'horizontal':
offsetType = 'offsetLeft';
break;
}
target_offset = $(target_id)[offsetType]; //distance to top of page for the target container
outer_offset = $(this.sid).down('.s_outer')[offsetType];
offset_from_top = target_offset - outer_offset;

this._to_scroll = offset_from_top;
this._incr = Math.ceil(Math.abs(offset_from_top) / 2);
new PeriodicalExecuter(
function(pe){
if (this._to_scroll <= this._incr) {
multiplier = 1
} else {
multiplier = -1
}
this.doScroll(multiplier * this._incr);
this._to_scroll += multiplier * this._incr;
this._incr = Math.ceil(this._incr / 2);
window.console.log(this._incr);
if (this._to_scroll * multiplier * -1 <= this._incr) {
this.doScroll(-1 * this._to_scroll); //the last scroll
pe.stop()
}
}.bind(this),
this.options.timeslice
);
return false;
}
})

2007-02-25

Mylar + Trac: yet another reason to use Eclipse

Filed Under:

Today I've wanted to change something in a trac instance I have setup for a project, when I thought: "I wish there was a way to do this from inside Eclipse". And there is! After a bit of searching (this information is available from the Trac site), I've discovered that Eclipse has a project that handles task based programming, project called Mylar, which has a Trac connector plugin financed through a Google Summer of Code project. I've installed the XML-RPC interface plugin for Trac, connected it to Eclipse and I can now enjoy viewing, creating and editing tickets in my Eclipse.

Laptop memory updated

Filed Under:

Thanks to the friendly guys at RDC Computers (boo Material Computers, who just turned their backs and said that they don't have it), I've upgraded the memory on my laptop. Now things have really started to fly. Before I only had 512 MB of RAM (which had to be shared with the onboard video card), but now I have a really cool 1.5 GB of RAM. I didn't want to go higher (to 2 GB) because I'm thinking that the 1.5 GB will be enough for what I'm doing (mostly programming) and there's no point of over-investing in this laptop (an HP Compaq NX 6125) which I'll probably replace in a year or two (if it won't fall to pieces in the meantime).

I couldn't be happier, there's a big difference in long term responsiveness of applications, especially as my workspace consists of KDE, Eclipse and Zope (2 & 3).

2007-02-21

Onwards to Gnome through Beryl and back to KDE

Filed Under:

I like my Linux to stay "on the edge", I like the excitement of knowing that on the next update you'll get new or improved software, which happens a lot in the Open Source world. So I've updated yesterday my laptop (a Compaq NX 6125) to the yet unreleased Ubuntu Feisty Fawn, an experienced that took almost 24 hours to have a fully working system at the end. I'll give some details of the problems encountered below.

Having a newly updated system and already with the practice of rebooting the machine, I've decided to try and fix the 3d acceleration, for which I had the fglrx binary driver  being loaded but which didn't give me 3d acceleration. First, I've tried the open source radeon driver (who's actual driver name in the xorg.conf file is still "ati"). It worked, but it still didn't give me 3d acceleration, as my card's 3d acceleration is unsuported (onboard ATI R200M).

Next on the list was to fix the fglrx. After I've uninstalled/reinstalled the fglrx driver and I've set the Composite option to Disable in the xorg.conf, I had 3d running. Plenty of details online, with guides and all, so this part was easy. While reading the documentation on the net about my card, it sparked my interest that some people had Beryl running on their laptops, with  the same card, so I've set myself on trying to get that running, to see what it's about. To make a long story short, the AIGLX extension from X.org 7.1 is not supported by the fglrx driver, so I've installed the XGL server (which is a replacement for the regular X server), and even if you see that the DRI extension is not supported by XGL and direct rendering is off, you'll still get accelerated rendering and, of course, beryl-xgl running.

To make XGL the default X server, I've changed my KDM file to something like this (taken from a recipe from the opensuse site):

[X-:*-Core]
AllowNullPasswd=true
AllowShutdown=All
NoPassEnable=true
NoPassUsers=tibi
#ServerArgsLocal=-nolisten tcp
#ServerCmd=/usr/bin/X -br
ServerCmd=/usr/bin/Xgl :0 -fullscreen -accel xv:pbuffer -accel glx:pbuffer
ServerArgsLocal=-nolisten tcp
OpenRepeat=5
OpenDelay=15
OpenTimeout=2000
ServerTimeout=60

KDE was slow with beryl, and with it XGL used 40% of the memory (at least apparently), while with Gnome XGL used only ~8%. So I've set myself to switch to Gnome, just to have the nice beryl effects, but in the end I've realized that, even though my Gnome desktop is really beautiful (nice Vista based fonts, nice icons similar to MacOSX) and its simplicity in working and workflow is something to appreciate, I still enjoy more in working with a system that is less "flashy" (no beryl effects) and closer to my philosophy as hacker and programer. That and being pissed off that I can't properly standby the laptop from Gnome, only from KDE and I'd still have to use KDM as login manager because GDM couldn't properly work with XGL, at least from what I've configured.

So now I'm back to my relatively non-flashy (but still nice looking, after some work) KDE.

And now some words about the Edgy > Feisty upgrade. In itself it went pretty much pain-free, not too many broken packages. There was one which I had to manually uninstall it before the dist-upgrade could continue, I forgot which. After the system was installed and I made sure that there were no more packages left to install, I've rebooted. The first reboots took a long time to complete (and I think the first one didn't even "make it"), so I've had to reboot in single mode and try the system from there. There were some problems with the network (the system complained about too many arguments for an iface in the /etc/networking/interfaces file) and no matter how much I've tried from KDE and Gnome, I couldn't properly configure the network with a static IP (it would get reseted to dynamic) so I had to remember the ifconfig/route lines, something I haven't use for more then 6 years. Somehow things are now fixed, probably after I've erased most of the options from that faulty interfaces file. The Enterprise Volume Management System took a really long time to boot, which it does on all Ubuntu systems I have, so I've changed the /etc/init.d/evms file to exit right at the top, after I couldn't figure out how it gets loaded and why my system needs it. My boot loading times are much faster now without it :-).

There's not much new, visually, in Gnome, except for a relatively ugly config window instead of the menu options. Why did they change that? I think I liked the menu system better. Of course, in terms of configuration windows preffered, I'm a fan of the old KControl, which I still run it when I need to configure something in KDE.

2007-02-16

Fresh meat for programmers

I've just discovered (or rediscovered) some resources that I think are important enough to highlight here.

  • The Zope Corporation has several eggs that are not published in the svn.zope.org subversion repository, eggs located at download.zope.org. There are several very interesting packages there, including some to build an intranet. I'll definately have a look at them.
  • I've rediscovered OpenJSAN, a Javascript repository full of goodies.
  • And its really nice Planet Javascript

2007-02-15

Using Zope Page Templates macros in other templates

Filed Under:

I won't try to discuss here the benefits of ZPT macros vs. viewlets and content providers or viceversa or when to use each of them, I'll just show a simple (basic even) technique of reusing template code across page templates, using the macros mechanism.

Trying to get the macros with something like context/@@page_with_macros/macros/the_macro doesn't work, as BrowserView (and BrowserPage) doesn't know anything about Zope Page Templates. Of course, that's also because Zope 3 doesn't directly publishes templates, only pages. The technique involves setting the page template who's macros you want to access as attributes of the curent page, something along these lines:

class MyPage(BrowserPage):rows
     macro_template = ViewPageTemplate('template_with_macros.pt)

In the template associated with this page, you can have:

<metal:macro metal:use-macro="view/macro_template/macros/the_macro">


2007-02-12

Using FCKEditor in Ajax views on Zope 3

Filed Under:

I'm working on a new, AJAX based application for a friend, which will run under Zope 3. Being a rather "CMS-ish" type of application, I need to provide an easy way to edit some rich text fields. I've settled on the FCKEditor, for which there is an already packaged library as zope.html (also depends on zope.file). I would have used TinyMCE, but I hit on a problem: all these visual editors have difficulties when loaded in "dynamic loaded views".

  • When using FCKEditor, everything seemed be fine for the first time, but the second time the editor was loaded, after the form was reloaded, there would be an error about a missing JavaScript object and the editor would fail to load. Form submission is handled by a function that serializes the form and makes an Ajax call, but the form object only contains the old values, not the new ones, as modified by the visual editor, so this had to be solved as well.
  • I love TinyMCE for being able to scale down in terms of interface very easily, but I couldn't make it work in my scenario just as easily, so I gave up. The editor would load just fine, but when submitting the form, the entire web page would be replaced by a white page and would continue to keep loading, without any results. I've found some mentioning of this problem on the web, and even in the TinyMCE wiki, but I couldn't work out what needs to be done in the short time that I had.

To solve the FCKEditor problems I had to do the following (blessed be the other bloggers of the Internet which already had to deal with this problem):

  • For the first problem, I've inserted the following snippet in the form header:
<script type="text/javascript">
FCKeditorAPI = null;
__FCKeditorNS = null;
FCKTools = null;
</script>
  • For the second problem, the form submit handler, I have the following code:
if (FCKeditorAPI) {
       for (instance in FCKeditorAPI.__Instances) {
           field_name = instance.toString();
           field_value = FCKeditorAPI.GetInstance(field_name).GetXHTML();
           sub_form[field_name].value = field_value;
       }
   }

While searching the net for other editors that might not have this problem, I've found this page that contains a big listing of all types of HTML visual editors. To tell the truth, in my use case, I'd be happy with something like Epoz (and I even have checked it on the web), but the project seems dead and I think I would have had to strip the zope/plone integration out of it.

After more then 6 or 7 years of not having to deal with JavaScript I'm very very rusty. Even for the most simple questions - like: how do you get the properties of an object? how do you check if an object has a property? how do you check if an object exists - I had to look at references. But it's all part of the learning experience, which fortunately, is the part that I enjoy most.

2007-02-11

First glance at Plone 3

Filed Under:

Thanks to the easy plone 3 buildout (plonout), I'm having my first look at the upcoming Plone 3. Some of the more evident changes:

  • Versioning is now possible thanks to CMFEditions, which means a "Save as version" option in the edit screen and a "Versions" page on objects.
  • The Kupu integration has been improved, the Kupu configlet offering new functions: the possibility to edit the toolbar, a new, streamlined interface to control the resource types and the possibility to replace the reference browser with a kupu drawer. In the edit screens kupu now has an "Anchor" button, which allows anchor insertion.
  • The interface hasn't changed at all, at least looking at its surface. Would this mean easy transition from older 2.1 - 2.5 sites to the new Plone 3.0?
  • wicked is integrated, meaning you can get easy wiki-like behaviour, "without the aftertaste of wikis"
  • The calendar has now a configlet, offering the old ZMI options accessible until now in portal_calendar
  • A configlet to specify the default mimetype for editable text fields (Types Settings)
  • The 'sharing' tab is back, with an improved interface
  • The different views on objects are loaded through AJAX and there's a "Loading" OSD that appears at the bottom of the page
  • In the Edit screen there is a "toolbar" at that top that uses AJAX to load several views that gather different settings that were spread among the Edit and Properties screens until now.
  • There is now a portlet management engine which allows portlet customizations. To me, at first look, this management page seemed extremely crowded and unintuitive. But this was just the first impression, after a minute of playing I already felt comfortable with it. Unfortunately, there's no "Simple HTML portlet", an option already offered by other portlet engines such as CMFContentPanels and the "Classic portlet" required knowing a template path and a macro nameb, but I'm sure this "Simple HTML portlet" is something that could be easily written. On the plus side, the portlet management engine offers the possibility to place portlets only for a specific group or for specific content types, which couldn't be easily done using CMFContentPanels.
  • There is a "rules" option in the action menu on the main page, which leads to several pages that allow defining actions based on conditions, but I couldn't get it to do much and didn't insist on it.

A lot of new, exciting stuff, without even looking under the hood (Zope 2.10, lots of zope 3 technology used, KSS and Ajax). I've encountered several bugs and there are several areas that could be improved, so it would be great if more people would download the ploneout and run Plone 3.0, at least to have a look, play with the new technologies and report the bugs. 

I presume that upgrading Plone 2.1/2.5 to Plone 3 would be relatively easy if there weren't many customizations done to the management interface, but this new technology also adds to the complexity of the Plone as application development framework. One last thing, if you haven't learned Zope 3 by now, start right now, it has become unavoidable in developing for Plone 3.

2007-02-10

Zope buildout quickstart

One of the bigger players in the latest move to automate Plone and Zope development and deployment has been buildout, so I figured it's about time to start learning it and see how it can help me. I'm writing this short recipe as I progress through learning buildout to help me remember this stuff later on.

Installing buildout

The easiest way to install buildout is to get easy_install (a manager for python packages) on your system. In order to get it installed, I had to do: (based on a custom python 2.4.3 installation in /opt/python):

$mkdir ~/buildout_play
$cd ~/buildout_play
$wget http://peak.telecommunity.com/dist/ez_setup.py
$sudo /opt/python/bin/python ez_setup.py

Next, install the zc.buildout package, using easy_install:

/opt/python/bin/easy_install zc.buildout

This will install the buildout egg in the python site-packages folder and create a 'buildout' script in the scripts folder, in my case /opt/python/bin/buildout.

Next, transform the buildout_play folder in buildout folder, by running:

/opt/python/bin/buildout -v

This will "bootstrap" that folder and prepare it as a buildout environment, also installing the setuptools and zc.buildout eggs. The buildout script will check every time it's being ran if those eggs are at their latest version, run it with the -N option if you want to skip that.

As a simple test for buildout, I've modified my buildout.cfg to contain the following lines:

[buildout]
parts = checkout

[checkout]
recipe = zc.recipe.zope3checkout
url = svn://svn.zope.org/repos/main/Zope3/trunk

This tells buildout to include a part named checkout, which is defined to use the "zc.recipe.zope3checkout" recipe, that is configured with the "url" option. Running

/opt/python/bin/buildout -v -N

will automatically grab the zc.recipe.zope3checkout egg, do a svn checkout in the parts/checkout folder and then compile in place the zope 3 checkout.

When developing new projects, to make this process easier, it is possible to put a bootstrap.py script in the folder where you're developing, which will automatically install setuptools (easy_install) and zc.buildout, transform that folder in a buildout folder and put a bin/bootstrap script that can be ran to do the build.

These are the basics to get started, see below for further details.

Reference

2007-02-06

The /@@/ resource view

Filed Under:

I recently encountered a problem that I presume would be pretty common when creating a site based on the z3c.layer.minimal browser layer: the resources, although accessible as ++resource++resource_name, are not accessible at the default location used by packages as zc.resourcelibrary: http://localhost/site/@@/resource_name

The reason, as I have guessed, was that a certain page or view was missing, not being registered for the IMinimalLayer, which doesn't inherit from the IBrowserDefaultLayer. Grepping for "@@" didn't yield anything meaningful, and left me struggling to understand how zope deals with pages. While searching on how to register new browser menus, I've encountered the @@ view declaration and imediately saw what the problem was: its declaration doesn't include the "@" character! After I've added the following registration in my zcml files, the problem dissapeared and resourcelibrary resources were finally found at their proper location:

    <configure package="zope.app.publisher.browser">

        <!-- Solves the resources lookup problem /@@/ -->

        <page name="" for="zope.app.component.interfaces.ISite"
            class="zope.app.publisher.browser.resources.Resources"
            permission="zope.Public"
            allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
            layer="act.coursebuilder.layer.common.ICourseBuilderCommonLayer" />

    </configure>

Better load time for Plone sites

Filed Under:

You probably know by now that Plone sites are better suited at content creation that content delivery. Still, the Plone solution is too good to pass even when creating simpler sites, where +99% of the trafic will be anonymous one. And when you have a good hammer, everything looks like a nail.

One of the various problems that Plone has when delivering this brochure type of websites is that the page weight is pretty high. On an average page that loads some images (a logo and a splash image), a Plone page can weight at about 500 kb. Pretty high, especially when the page doesn't seem too "different". The Javascript files loaded for this page are about one third of its weight and probably not used, if your website doesn't use the livesearch, search engine word highlight, internal search word highlight, the icons for external links or any other "gimmicks" that Plone uses to enhance the user experience.

To prevent these files to load for the anonymous user, place the following condition for the undersired javascript files in portal_javascripts:

python: not portal.portal_membership.isAnonymousUser()

In my case, after some testing, I've decided to leave the following files untouched, to make it possible for site editors to login from the site:

register_function.js
plone_javascript_variables.js
cookie_functions.js
login.js

Next, a look at the css files that are being loaded will show some possibility for improvement there as well, but not as dramatic. Many of the files there can be conditioned with the same line as above, but this depends on the type of website being developed.

You can enable the debug mode for both portal_javascripts and portal_css to help observe which file gets loaded. Of course, placing those conditions in portal_javascripts and portal_css will probably most likely increase the load on the server, but the trade-off is probably worth it.

And finally, enabling mod_cache and mod_deflate for the website will help even further reduce the number of bytes needed to be loaded from the Plone site.

Weblog
Atom
RDF
RSS 2.0
Powered by Quills
Technorati
Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: