roller-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From snoopd...@apache.org
Subject svn commit: r828908 - in /roller/trunk/apps/weblogger: src/java/org/apache/roller/weblogger/ui/struts2/editor/ web/WEB-INF/ web/WEB-INF/classes/ web/WEB-INF/jsps/editor/ web/roller-ui/styles/
Date Fri, 23 Oct 2009 01:33:49 GMT
Author: snoopdave
Date: Fri Oct 23 01:33:48 2009
New Revision: 828908

URL: http://svn.apache.org/viewvc?rev=828908&view=rev
Log:
Export to Movable Type / Wordpress format 
https://issues.apache.org/jira/browse/ROL-1822

Added:
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java
    roller/trunk/apps/weblogger/web/WEB-INF/jsps/editor/WeblogExport.jsp
Modified:
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/editor-menu.xml
    roller/trunk/apps/weblogger/web/WEB-INF/classes/ApplicationResources.properties
    roller/trunk/apps/weblogger/web/WEB-INF/classes/struts.xml
    roller/trunk/apps/weblogger/web/WEB-INF/tiles.xml
    roller/trunk/apps/weblogger/web/roller-ui/styles/layout.css
    roller/trunk/apps/weblogger/web/roller-ui/styles/roller.css

Added: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java?rev=828908&view=auto
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java
(added)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java
Fri Oct 23 01:33:48 2009
@@ -0,0 +1,407 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.roller.weblogger.ui.struts2.editor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.weblogger.WebloggerException;
+import org.apache.roller.weblogger.business.MediaFileManager;
+import org.apache.roller.weblogger.business.URLStrategy;
+import org.apache.roller.weblogger.business.WeblogEntryManager;
+import org.apache.roller.weblogger.business.WebloggerFactory;
+import org.apache.roller.weblogger.pojos.MediaFile;
+import org.apache.roller.weblogger.pojos.MediaFileDirectory;
+import org.apache.roller.weblogger.pojos.WeblogEntry;
+import org.apache.roller.weblogger.pojos.WeblogPermission;
+import org.apache.roller.weblogger.pojos.wrapper.WeblogEntryCommentWrapper;
+import org.apache.roller.weblogger.pojos.wrapper.WeblogEntryWrapper;
+import org.apache.roller.weblogger.ui.struts2.util.UIAction;
+import org.apache.struts2.interceptor.ServletResponseAware;
+
+/**
+ * Provides export functionality for the author of a weblog.
+ */
+public final class WeblogExport extends UIAction
+        implements ServletResponseAware {
+
+    // Static Variables --------------------------------------------------------
+    private static final Log log = LogFactory.getLog(WeblogExport.class);
+    /** Used to replace <foo bar="foobar"/> with <foo bar="foobar" /> **/
+    private static final Pattern BAD_SELF_CLOSING_TAG = Pattern.compile(
+            "(([\\S])(/>))");
+    // TODO: Add enum to manage the different MT constants
+    private static final String MT_SECTION_DIVIDER = "-----\n";
+    private static final String MT_ENTRY_DIVIDER = "--------\n";
+    private static final SimpleDateFormat MT_DATE_FORMAT = new SimpleDateFormat(
+            "MM/dd/yyyy HH:mm:ss");
+    // Instance Variables ------------------------------------------------------
+    private HttpServletResponse response;
+    private String baseUrl;
+    private List<WeblogEntryWrapper> entries;
+    private Pattern baseUrlPattern;
+
+    // Constructors ------------------------------------------------------------
+    public WeblogExport() {
+        this.actionName = "weblogExport";
+        this.desiredMenu = "editor";
+        this.pageTitle = "weblogExport.title";
+
+        this.entries = new ArrayList<WeblogEntryWrapper>();
+    }
+
+    // Public Methods ----------------------------------------------------------
+    /**
+     * Keeps a reference to the current HTTP servlet response object.
+     *
+     * @param httpServletResponse The HTTP servlet response.
+     */
+    public void setServletResponse(HttpServletResponse httpServletResponse) {
+        this.response = httpServletResponse;
+    }
+
+    /**
+     * Sets the base URL to be used when replacing references to resource files.
+     *
+     * @param baseUrl The desired base URL.
+     */
+    public void setBaseUrl(String baseUrl) {
+        this.baseUrl = baseUrl;
+    }
+
+    /**
+     * Require the author role before allowing export functionality.
+     */
+    @Override
+    public List<String> requiredWeblogPermissionActions() {
+        return Collections.singletonList(WeblogPermission.ADMIN);
+    }
+
+    /**
+     * Simply triggers the display of the export options UI.
+     */
+    @Override
+    public String execute() {
+        // We need to gather some more info before we can attempt an export
+        return INPUT;
+    }
+
+    /**
+     * Returns an output stream to the client containing a text file of all
+     * entries and comments. This will include draft entries as well.
+     *
+     * Currently the only file format supported is mtimport.
+     */
+    public void exportEntries() {
+        try {
+            WeblogEntryManager wmgr =
+                    WebloggerFactory.getWeblogger().getWeblogEntryManager();
+
+            URLStrategy urlStrategy;
+            urlStrategy = WebloggerFactory.getWeblogger().getUrlStrategy();
+
+            List rawEntries;
+            rawEntries = wmgr.getWeblogEntries(getActionWeblog(), null, null,
+                    null, null, null, null, null, null, null, null, 0, -1);
+
+            for (Object entry : rawEntries) {
+                entries.add(WeblogEntryWrapper.wrap((WeblogEntry) entry,
+                        urlStrategy));
+            }
+
+            // Compile the resource URL pattern using the weblog handle
+            baseUrlPattern = Pattern.compile(
+                    "(<[ \\S]+=[\"'])(http[s]*://[\\S]+/" +
+                    getActionWeblog().getHandle() + "/resource/|/" +
+                    getActionWeblog().getHandle() + "/resource/)");
+
+            String output;
+            output = formatAsMoveableType(entries);
+
+            if (!response.isCommitted()) {
+                response.reset();
+
+                SimpleDateFormat dateFormat;
+                dateFormat = new SimpleDateFormat("MMddyyyy'T'HHmmss");
+
+                StringBuilder fileName;
+                fileName = new StringBuilder();
+                fileName.append(getActionWeblog().getHandle());
+                fileName.append("-entries-");
+                fileName.append(dateFormat.format(System.currentTimeMillis()));
+                fileName.append(".txt");
+
+                response.setContentType("text/plain; charset=utf-8");
+                response.setHeader("Content-Disposition",
+                        "attachment; filename=\"" + fileName.toString() + "\"");
+
+                ServletOutputStream outputStream;
+                outputStream = response.getOutputStream();
+                outputStream.print(output);
+                outputStream.flush();
+                outputStream.close();
+            }
+        } catch (WebloggerException e) {
+            log.error("Error looking up entries: ", e);
+        } catch (IOException e) {
+            log.error("Error getting output stream: ", e);
+        }
+    }
+
+    /**
+     * Returns an output stream to the client of all uploaded resource files as
+     * a ZIP archive.
+     */
+    public void exportResources() {
+        SimpleDateFormat dateFormat;
+        dateFormat = new SimpleDateFormat("MMddyyyy'T'HHmmss");
+
+        StringBuilder fileName;
+        fileName = new StringBuilder();
+        fileName.append(getActionWeblog().getHandle());
+        fileName.append("-resources-");
+        fileName.append(dateFormat.format(System.currentTimeMillis()));
+        fileName.append(".zip");
+
+        if (!response.isCommitted()) {
+            response.reset();
+
+            response.setContentType("application/zip");
+            response.setHeader("Content-Disposition",
+                    "attachment; filename=\"" + fileName.toString() + "\"");
+
+            try {
+                MediaFileManager fmgr =
+                        WebloggerFactory.getWeblogger().getMediaFileManager();
+
+                List<MediaFile> resources = new ArrayList<MediaFile>();
+
+                // Load the contents of any sub-directories
+                for (MediaFileDirectory mdir : fmgr.getMediaFileDirectories(getActionWeblog()))
{
+                    loadResources(resources, mdir);
+                }
+
+                // Load the files at the root of the specific upload directory
+                loadResources(resources, null);
+
+                // Create a buffer for reading the files
+                byte[] buffer;
+                buffer = new byte[1024];
+
+                ServletOutputStream servletOutput;
+                servletOutput = response.getOutputStream();
+
+                ZipOutputStream zipOutput;
+                zipOutput = new ZipOutputStream(servletOutput);
+
+                for (MediaFile resource : resources) {
+                    InputStream input;
+                    input = resource.getInputStream();
+
+                    // Add a new ZIP entry to output stream
+                    zipOutput.putNextEntry(new ZipEntry(resource.getPath()));
+
+                    int length;
+                    while ((length = input.read(buffer)) > 0) {
+                        zipOutput.write(buffer, 0, length);
+                    }
+
+                    // Cleanup the entry
+                    input.close();
+                    zipOutput.closeEntry();
+                }
+
+                // Cleanup the output stream
+                zipOutput.flush();
+                zipOutput.close();
+            } catch (Exception e) {
+                log.error("Error exporting resources: " + e.getMessage());
+            }
+        }
+    }
+
+    // Private Methods ---------------------------------------------------------
+    /**
+     * Formats all entries and comments, including draft entries, in the
+     * Moveable Type import format (mtimport). This format can be imported
+     * into both Moveable Type and WordPress blogging platforms.
+     *
+     * @param entries A collection of entries to format.
+     * @return A String of all entries and comments formatted as mtimport
+     */
+    private String formatAsMoveableType(List<WeblogEntryWrapper> entries) {
+        StringBuilder result;
+        result = new StringBuilder();
+
+        for (WeblogEntryWrapper entry : entries) {
+            // Author
+            result.append("AUTHOR: ");
+            result.append(entry.getCreator().getScreenName());
+            result.append("\n");
+
+            // Title
+            result.append("TITLE: ");
+            result.append(entry.getTitle());
+            result.append("\n");
+
+            // Date
+            result.append("DATE: ");
+            if (entry.getStatus().equals(WeblogEntry.PUBLISHED)) {
+                result.append(MT_DATE_FORMAT.format(entry.getPubTime()));
+            } else {
+                result.append(MT_DATE_FORMAT.format(entry.getUpdateTime()));
+            }
+            result.append("\n");
+
+            // Primary category
+            result.append("PRIMARY CATEGORY: ");
+            result.append(entry.getCategory().getName());
+            result.append("\n");
+
+            // Status
+            result.append("STATUS: ");
+            if (entry.getStatus().equals(WeblogEntry.PUBLISHED)) {
+                result.append("publish");
+            } else {
+                result.append("draft");
+            }
+            result.append("\n");
+
+            // Allow comments
+            result.append("ALLOW COMMENTS: ");
+            if (entry.getAllowComments()) {
+                result.append("1");
+            } else {
+                result.append("0");
+            }
+            result.append("\n");
+
+            result.append(MT_SECTION_DIVIDER);
+
+            // Body
+            result.append("BODY: \n");
+            result.append(processEntry(entry.getText().trim()));
+            result.append("\n");
+
+            result.append(MT_SECTION_DIVIDER);
+
+            // Excerpt
+            if (entry.getSummary() != null && !entry.getSummary().equals("")) {
+                result.append("EXCERPT: \n");
+                result.append(processEntry(entry.getSummary().trim()));
+                result.append("\n");
+
+                result.append(MT_SECTION_DIVIDER);
+            }
+
+            for (Object commentObj : entry.getComments()) {
+                WeblogEntryCommentWrapper comment;
+                comment = (WeblogEntryCommentWrapper) commentObj;
+                result.append("COMMENT: \n");
+
+                result.append("AUTHOR: ");
+                result.append(comment.getName());
+                result.append("\n");
+
+                result.append("EMAIL: ");
+                result.append(comment.getEmail());
+                result.append("\n");
+
+                result.append("URL: ");
+                result.append(comment.getUrl());
+                result.append("\n");
+
+                result.append("DATE: ");
+                result.append(MT_DATE_FORMAT.format(comment.getPostTime()));
+                result.append("\n");
+
+                result.append(comment.getContent());
+                result.append("\n");
+
+                result.append(MT_SECTION_DIVIDER);
+            }
+
+            result.append(MT_ENTRY_DIVIDER);
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Performs some pre-processing of entry text. It fixes a problem when
+     * WordPress imports a self-closing HTML tag that does not have a space
+     * preceding the "/>" characters. It also provides a replacment base URL
+     * for all referenced resource files if requested.
+     *
+     * @param text The entry text to process.
+     * @return The resulting String after processing has taken place.
+     */
+    private String processEntry(String text) {
+        String result;
+
+        // Fix self closing tags that are missing a space
+        Matcher badSelfClosingTagMatcher;
+        badSelfClosingTagMatcher = BAD_SELF_CLOSING_TAG.matcher(text);
+
+        result = badSelfClosingTagMatcher.replaceAll("$2 />");
+
+        // Replace all /weblog-handle/resource/ links with a specified base URL
+        if (baseUrl != null && !baseUrl.equals("")) {
+            Matcher baseUrlMatcher;
+            baseUrlMatcher = baseUrlPattern.matcher(result);
+
+            try {
+                result = baseUrlMatcher.replaceAll("$1" + baseUrl);
+            } catch (IllegalArgumentException e) {
+                log.error("Invalid base URL submitted: " + baseUrl + ": " +
+                        e.getMessage());
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Adds all the non-directory files for the specified path to the provided
+     * List.
+     *
+     * @param resources The List in which to add the resource objects.
+     * @param path The path from which to load. If null, the root path is used.
+     */
+    private void loadResources(List<MediaFile> mfiles, MediaFileDirectory mdir) {
+        try {
+            // Load the non-directory files
+            mfiles.addAll(mdir.getMediaFiles());
+        } catch (Exception e) {
+            log.error("Error load resources: " + e.getMessage());
+        }
+    }
+}

Modified: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/editor-menu.xml
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/editor-menu.xml?rev=828908&r1=828907&r2=828908&view=diff
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/editor-menu.xml
(original)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/editor/editor-menu.xml
Fri Oct 23 01:33:48 2009
@@ -59,7 +59,13 @@
                    perms="post"
                    subactions="mediaFileAdd,mediaFileHierarchicalView,mediaFileSearch" />
 
-        <menu-item action="referrers"     
+        <menu-item action="weblogExport"
+                   name="tabbedmenu.weblog.export"
+                   roles="editor"
+                   perms="author"
+                   subactions="exportEntries,exportResources"/>
+
+         <menu-item action="referrers"
                    name="tabbedmenu.weblog.referers" 
                    globalPerms="login"
                    weblogPerms="post" 

Modified: roller/trunk/apps/weblogger/web/WEB-INF/classes/ApplicationResources.properties
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/web/WEB-INF/classes/ApplicationResources.properties?rev=828908&r1=828907&r2=828908&view=diff
==============================================================================
--- roller/trunk/apps/weblogger/web/WEB-INF/classes/ApplicationResources.properties (original)
+++ roller/trunk/apps/weblogger/web/WEB-INF/classes/ApplicationResources.properties Fri Oct
23 01:33:48 2009
@@ -1754,6 +1754,26 @@
 uploadFiles.error.upload=Upload failed for [{0}]
 uploadFiles.error.delete=Delete failed for [{0}], possibly a non-empty directory?
 
+# ----------------------------------------------------------------------- Export
+
+weblogExport.title=Export Weblog
+weblogExport.subtitle=Export the weblog <span>{0}</span>
+weblogExport.tip=Exporting your weblog is great for locally backing up your \
+  entries, comments and uploaded files.
+
+weblogExport.entries=Entries
+weblogExport.entries.tip=Export all of your entries and comments in the \
+  Moveable Type import format. This format can also be used with WordPress. \
+  You may optionally define a new base URL for all of your referenced \
+  resource files.
+weblogExport.baseUrl=Base Resource URL (Optional):
+weblogExport.exportEntries=Export Entries
+
+weblogExport.resources=Resources
+weblogExport.resources.tip=Export all of your uploaded resource files as a \
+  convenient ZIP archive.
+weblogExport.exportResources=Export Resources
+
 # ------------------------------------------------------------------- User admin
 
 userAdmin.title.searchUser=Find user to edit

Modified: roller/trunk/apps/weblogger/web/WEB-INF/classes/struts.xml
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/web/WEB-INF/classes/struts.xml?rev=828908&r1=828907&r2=828908&view=diff
==============================================================================
--- roller/trunk/apps/weblogger/web/WEB-INF/classes/struts.xml (original)
+++ roller/trunk/apps/weblogger/web/WEB-INF/classes/struts.xml Fri Oct 23 01:33:48 2009
@@ -364,6 +364,12 @@
                 class="org.apache.roller.weblogger.ui.struts2.editor.Resources">
             <result name="list" type="tiles">.Resources</result>
         </action>
+
+        <action name="weblogExport!*" method="{1}"
+                class="org.apache.roller.weblogger.ui.struts2.editor.WeblogExport">
+            <result name="input" type="tiles">.WeblogExport</result>
+            <!--<result name="success" type="chain">weblogExport</result>-->
+        </action>
         
         <action name="referrers!*" method="{1}"
                 class="org.apache.roller.weblogger.ui.struts2.editor.Referrers">

Added: roller/trunk/apps/weblogger/web/WEB-INF/jsps/editor/WeblogExport.jsp
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/web/WEB-INF/jsps/editor/WeblogExport.jsp?rev=828908&view=auto
==============================================================================
--- roller/trunk/apps/weblogger/web/WEB-INF/jsps/editor/WeblogExport.jsp (added)
+++ roller/trunk/apps/weblogger/web/WEB-INF/jsps/editor/WeblogExport.jsp Fri Oct 23 01:33:48
2009
@@ -0,0 +1,50 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  The ASF licenses this file to You
+  under the Apache License, Version 2.0 (the "License"); you may not
+  use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.  For additional information regarding
+  copyright in this work, please see the NOTICE file in the top level
+  directory of this distribution.
+-->
+<%@ include file="/WEB-INF/jsps/taglibs-struts2.jsp" %>
+
+<p class="subtitle">
+    <s:text name="weblogExport.subtitle" >
+        <s:param value="actionWeblog.handle" />
+    </s:text>
+</p>
+
+<p class="pagetip">
+    <s:text name="weblogExport.tip" />
+</p>
+
+<h2><s:text name="weblogExport.entries" /></h2>
+<p class="pagetip" style="width:50%"><s:text name="weblogExport.entries.tip" /></p>
+<s:form name="entriesExport" action="weblogExport!exportEntries" method="POST">
+    <p>
+        <s:text name="weblogExport.baseUrl"/>
+        <s:textfield name="baseUrl" size="30" />
+    </p>
+    <p>
+        <s:submit key="weblogExport.exportEntries" />
+        <s:hidden name="weblog" />
+    </p>
+</s:form>
+
+<h2><s:text name="weblogExport.resources" /></h2>
+<p class="pagetip" style="width:50%"><s:text name="weblogExport.resources.tip" /></p>
+<p>
+    <s:form name="resourcesExport" action="weblogExport!exportResources" method="POST">
+        <s:submit key="weblogExport.exportResources" />
+        <s:hidden name="weblog" />
+    </s:form>
+</p>

Modified: roller/trunk/apps/weblogger/web/WEB-INF/tiles.xml
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/web/WEB-INF/tiles.xml?rev=828908&r1=828907&r2=828908&view=diff
==============================================================================
--- roller/trunk/apps/weblogger/web/WEB-INF/tiles.xml (original)
+++ roller/trunk/apps/weblogger/web/WEB-INF/tiles.xml Fri Oct 23 01:33:48 2009
@@ -386,8 +386,11 @@
     <definition name=".Referrers" extends=".tiles-tabbedpage" >
         <put-attribute name="content" value="/WEB-INF/jsps/editor/Referrers.jsp" />
     </definition>
-    
-    
+
+    <definition name=".WeblogExport" extends=".tiles-tabbedpage" >
+        <put-attribute name="content" value="/WEB-INF/jsps/editor/WeblogExport.jsp" />
+    </definition>
+
     <!-- weblog admin pages (and associates) -->
     <definition name=".WeblogConfig" extends=".tiles-tabbedpage" >
         <put-attribute name="content" value="/WEB-INF/jsps/editor/WeblogConfig.jsp" />

Modified: roller/trunk/apps/weblogger/web/roller-ui/styles/layout.css
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/web/roller-ui/styles/layout.css?rev=828908&r1=828907&r2=828908&view=diff
==============================================================================
--- roller/trunk/apps/weblogger/web/roller-ui/styles/layout.css (original)
+++ roller/trunk/apps/weblogger/web/roller-ui/styles/layout.css Fri Oct 23 01:33:48 2009
@@ -65,6 +65,7 @@
 }
 #centercontent {
     margin: 10px;
+    padding-left: 0.5em;
 }
 #rightcontent_wrap {
     float: right;

Modified: roller/trunk/apps/weblogger/web/roller-ui/styles/roller.css
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/web/roller-ui/styles/roller.css?rev=828908&r1=828907&r2=828908&view=diff
==============================================================================
--- roller/trunk/apps/weblogger/web/roller-ui/styles/roller.css (original)
+++ roller/trunk/apps/weblogger/web/roller-ui/styles/roller.css Fri Oct 23 01:33:48 2009
@@ -820,6 +820,7 @@
 #menu h1 {
     line-height:120%;
     margin:15px 0px;
+    padding-left: 0.5em;
 }
 #ewecontextmenu {
     background-color:#CECECE;



Mime
View raw message