# HG changeset patch
# User Josef Meier <jo.meier@gmx.de>
# Date 1258914915 -3600
# Node ID 2e2bce28e785279f554a9188070f627193d8644e
# Parent af42eec12f386db44f3d104327c16fbec67a486d
Improved attachment dialog for GUI editor.

New features:
- available attachments are listed in a drop down list
- also attachments for a different page can be fetched and listed in the drop down list.
- new attachments can be created.
- error messages like 'Page doesn't exist', ...
- i18n support

--- a/MoinMoin/action/fckdialog.py	Sat Nov 21 16:31:36 2009 +0100
+++ b/MoinMoin/action/fckdialog.py	Sun Nov 22 19:35:15 2009 +0100
@@ -7,6 +7,8 @@
 """
 
 from MoinMoin import config, wikiutil
+from MoinMoin.action.AttachFile import _get_files
+from MoinMoin.Page import Page
 import re
 
 ##############################################################################
@@ -357,38 +359,87 @@
 </html>
 ''' % locals())
 
-##############################################################################
-### Attachment dialog
-##############################################################################
 
 def attachment_dialog(request):
-    # list of wiki pages
-    name = request.values.get("pagename", "")
-    if name:
-        from MoinMoin import search
-        # XXX error handling!
-        searchresult = search.searchPages(request, 't:"%s"' % name)
-
-        pages = [p.page_name for p in searchresult.hits]
-        pages.sort()
-        pages[0:0] = [name]
-        page_list = '''
-         <tr>
-          <td colspan=2>
-           <select id="sctPagename" size="1" onchange="OnChangePagename(this.value);">
-           %s
-           </select>
-          <td>
-         </tr>
-''' % "\n".join(['<option value="%s">%s</option>' % (page, page)
-                 for page in pages])
-    else:
-        page_list = ""
+    """ Attachment dialog for GUI editor. """
+    """ Features: This dialog can... """
+    """ - list attachments in a drop down list """
+    """ - list attachments also for a different page than the current one """
+    """ - create new attachment """
+    _ = request.getText
+    url_prefix_static = request.cfg.url_prefix_static
 
     # wiki url
-    url_prefix_static = request.cfg.url_prefix_static
-    scriptname = request.script_root + '/'
+    scriptname = request.getScriptname()
+    if not scriptname or not scriptname.endswith('/'):
+        scriptname += "/"
     action = scriptname
+
+    # The following code lines implement the feature "list attachments for a different page".
+    # Meaning of the variables:
+    # - requestedPagename : Name of the page where attachments shall be listed from.
+    # - attachmentsPagename : Name of the page where the attachments where retrieved from.
+    # - destinationPagename : Name of the page where attachment will be placed on.
+
+    requestedPagename = request.values.get("requestedPagename", "")
+    destinationPagename = wikiutil.escape(request.values.get("destinationPagename", request.page.page_name))
+
+    if requestedPagename == "":
+        attachmentsPagename = request.page.page_name
+    else:
+        attachmentsPagename = requestedPagename
+
+    attachments = []
+    page = Page(request, attachmentsPagename)
+    if page.exists():
+        attachments = _get_files(request, attachmentsPagename)
+
+        if not attachments:
+            status = 1 # No attachments on this page.
+            firstDropDownEntry = "<%s>" % _("No attachments found")
+        else:
+            status = 2 # Attachments found.
+            firstDropDownEntry = "<%s>" % _("Select")
+            attachments.sort()
+    else:
+        status = 0 # Page not found.
+        firstDropDownEntry = "<%s>" % _("Page not found")
+
+    attachments.insert(0, wikiutil.escape(firstDropDownEntry))
+    attachmentList = '''
+        <select id="sctAttachments" size="1" style="width:100%%">
+        %s
+        </select>
+''' % "\n".join(['<option value="%s">%s</option>' % (attachment, attachment)
+                 for attachment in attachments])
+
+    # Translation of dialog texts.
+    langRadioSelectAttachment = _("Select existing attachment")
+    langRadioCreateNewAttachment = _("Create new attachment")
+    langListAttachmentsButton = _("List attachments")
+    langListAttachmentsForPage = _("List attachments for page:")
+    langAttachmentList = _("Attachments")
+    langNameNewAttachment = _("Name of the attachment")
+    langNewAttachmentFormat = wikiutil.escape("%s: <%s></><%s>" % (_("Format"), _("Pagename"), _("Attachment name")))
+    langExamples = _("Examples:")
+    langExample1 = _("('test.pdf' is on current page)")
+    langExample2 = _("('test.pdf' is on page 'test')")
+    langExample3 = _("('test.pdf' is on page 'test1/test2')")
+    langFurtherInfo = _("After you saved the page, an attachment symbol will be visible.")
+
+    # Translation for the javascript part of this dialog.
+    langPageAttachmentNotFound = _("Page '%s' (and attachment '%s') not found!")
+    langPageNotFound = _("Page '%s' not found!")
+    langAttachmentNotFound = _("Attachment '%s' couldn't be found on page '%s'!\n\nAdd this attachment before using it.")
+    langAttachmentNotFoundMarker = _("Not found: %s")
+    langAlertMissingPageName = _("Please enter a page name!")
+    langAlertMissingAttachment = _("Please select an attachment from the drop down list!")
+    langAlertInvalidDropDownList = _(""
+"You entered a different page's name.\nTherefore the content of the current "
+"drop down list is invalid now.\n\nPlease press the button 'List attachments' "
+"to get attachments for the remote page!")
+    langAlertMissingNewAttachmentName = _("Please enter a name for the new attachment!")
+
     request.write('''
 <!--
  * FCKeditor - The text editor for internet
@@ -422,31 +473,101 @@
   <script src="%(url_prefix_static)s/applets/moinFCKplugins/moinurllib.js" type="text/javascript"></script>
  </head>
  <body scroll="no" style="OVERFLOW: hidden">
-  <div id="divInfo">
-   <div id="divLinkTypeAttachment">
-    <table height="100%%" cellSpacing="0" cellPadding="0" width="100%%" border="0">
-     <tr>
-      <td>
-       <form action=%(action)s method="GET">
-       <input type="hidden" name="action" value="fckdialog">
-       <input type="hidden" name="dialog" value="attachment">
-       <table cellSpacing="0" cellPadding="0" align="center" border="0">
+    <form id="DlgAttachmentForm" name="DlgAttachmentForm" action=%(action)s method="GET">
+    <input type="hidden" name="action" value="fckdialog">
+    <input type="hidden" name="dialog" value="attachment">
+    <input type="hidden" id="requestedPagename" name="requestedPagename" value="%(requestedPagename)s">
+    <input type="hidden" id="attachmentsPagename" name="attachmentsPagename" value="%(attachmentsPagename)s">
+    <input type="hidden" id="destinationPagename" name="destinationPagename" value="%(destinationPagename)s">
+    <input type="hidden" id="status" name="status" value="%(status)s">
+    <input type="hidden" id="langPageAttachmentNotFound" value="%(langPageAttachmentNotFound)s">
+    <input type="hidden" id="langPageNotFound" value="%(langPageNotFound)s">
+    <input type="hidden" id="langAttachmentNotFound" value="%(langAttachmentNotFound)s">
+    <input type="hidden" id="langAttachmentNotFoundMarker" value="%(langAttachmentNotFoundMarker)s">
+    <input type="hidden" id="langAlertMissingPageName" value="%(langAlertMissingPageName)s">
+    <input type="hidden" id="langAlertMissingAttachment" value="%(langAlertMissingAttachment)s">
+    <input type="hidden" id="langAlertInvalidDropDownList" value="%(langAlertInvalidDropDownList)s">
+    <input type="hidden" id="langAlertMissingNewAttachmentName" value="%(langAlertMissingNewAttachmentName)s">
+
+    <div id="divInfo" style="valign=top;">
+    <div id="divLinkTypeAttachment">
+    <table cellSpacing="0" cellPadding="0" width="100%%" border="0">
         <tr>
-         <td>
-          <span fckLang="AttachmentDlgName">Attachment Name</span><br>
-          <input id="txtAttachmentname" name="pagename" size="30" value="%(name)s">
-         </td>
+            <td>
+                <input type="radio" name="radioCreateSelectAttachment" id="radioSelectAttachment" value="1" onchange="OnCreateSelectChange();">
+            </td>
+            <td>
+                <span id="DlgRadioSelectAttachment">%(langRadioSelectAttachment)s</span><br>
+            </td>
         </tr>
-       </table>
-       </form>
-      </td>
-     </tr>
+        <tr>
+            <td>
+                &nbsp;
+            </td>
+            <td>
+                <fieldset>
+                    <table cellSpacing="0" cellPadding="0" width="100%%" border="0">
+                        <tr width="100%%">
+                            <td valign="bottom" style="width:100%%" style="padding-top:10px">
+                                <span id="DlgAttachmentPage">%(langListAttachmentsForPage)s</span><br>
+                                <input id="txtAttachmentPagename" type="text" onkeyup="OnAttachmentPagenameChange();" onchange="OnAttachmentPagenameChange();" style="width:100%%">
+                            </td>
+                            <td valign="bottom" style="padding-left:10px">
+                                <input id=btnListAttachments type="submit" value="%(langListAttachmentsButton)s">
+                            </td>
+                        </tr>
+                        <tr>
+                            <td valign="top" style="padding-top:10px">
+                                <span id="DlgAttachmentList">%(langAttachmentList)s</span><br>
+                                %(attachmentList)s
+                            </td>
+                            <td>
+                                &nbsp;
+                            </td>
+                        </tr>
+                    </table>
+                </fieldset>
+            </td>
+        </tr>
+        <tr>
+            <td>
+                <input type="radio" name="radioCreateSelectAttachment" id="radioCreateAttachment" value="2" onchange="OnCreateSelectChange();">
+            </td>
+            <td>
+                <span id="DlgRadioCreateAttachment">%(langRadioCreateNewAttachment)s</span><br>
+            </td>
+        </tr>
+        <tr>
+            <td>
+                &nbsp;
+            </td>
+            <td>
+                <fieldset>
+                    <table cellSpacing="0" cellPadding="0" width="100%%" border="0">
+                        <tr>
+                            <td>
+                                <span id="DlgNewAttachmentName">%(langNameNewAttachment)s</span><br>
+                                <input id="txtNewAttachmentName" size="30" type="text"><br>
+                                <span id="DlgNewAttachmentInfo">%(langNewAttachmentFormat)s<br>
+                                %(langExamples)s<br>
+                                <span><ul><li><b><i>test.pdf</i></b> %(langExample1)s</li>
+                                <li><b><i>test/test.pdf</i></b> %(langExample2)s</li>
+                                <li><b><i>test1/test2/test.pdf</i></b> %(langExample3)s</li></ul></span>
+                                %(langFurtherInfo)s</span>
+                            </td>
+                        </tr>
+                    </table>
+                </fieldset>
+            </td>
+        </tr>
     </table>
    </div>
   </div>
+   </form>
  </body>
 </html>
 ''' % locals())
+
 
 ##############################################################################
 ### Image dialog
--- a/MoinMoin/web/static/htdocs/applets/moinFCKplugins/moinattachment/fck_attachment.js	Sat Nov 21 16:31:36 2009 +0100
+++ b/MoinMoin/web/static/htdocs/applets/moinFCKplugins/moinattachment/fck_attachment.js	Sun Nov 22 19:35:15 2009 +0100
@@ -18,22 +18,12 @@
  *   Frederico Caldeira Knabben (fredck@fckeditor.net)
  */
 
-var dialog	= window.parent ;
-var oEditor = dialog.InnerDialogLoaded() ;
+var dialog	= window.parent;
+var oEditor = dialog.InnerDialogLoaded();
 var FCK   = oEditor.FCK;
 var FCKLang  = oEditor.FCKLang;
 var FCKConfig = oEditor.FCKConfig;
-
-//#### Dialog Tabs
-
-// Set the dialog tabs.
-window.parent.AddTab('Info', FCKLang.DlgLnkInfoTab);
-
-// Function called when a dialog tag is selected.
-function OnDialogTabChange(tabCode)
-{
- ShowE('divInfo'  , (tabCode == 'Info'));
-}
+var invalidAttachmentList = false;
 
 //#### Regular Expressions library.
 var oRegex = new Object();
@@ -57,105 +47,378 @@
 //#### Initialization Code
 
 // oLink: The actual selected link in the editor.
-var oLink = dialog.Selection.GetSelection().MoveToAncestorNode( 'A' ) ;
-if ( oLink )
-  FCK.Selection.SelectNode( oLink ) ;
+var oLink = dialog.Selection.GetSelection().MoveToAncestorNode('A');
+if (oLink)
+  FCK.Selection.SelectNode(oLink);
 
 window.onload = function()
 {
- // Translate the dialog box texts.
- oEditor.FCKLanguageManager.TranslatePage(document);
+  // Translate the dialog box texts.
+  oEditor.FCKLanguageManager.TranslatePage(document);
 
- // Load the selected link information (if any).
- LoadSelection();
+  // Load the selected link information (if any).
+  LoadSelection();
 
- // Show the initial dialog content.
- GetE('divInfo').style.display = '';
+  // Initialize the user interface.
+  var attachmentsPagename = GetE('attachmentsPagename').value;
+  GetE('requestedPagename').value = attachmentsPagename;
+  GetE('txtAttachmentPagename').value = attachmentsPagename;
 
- // Activate the "OK" button.
- window.parent.SetOkButton(true);
+  GetE('radioSelectAttachment').checked = true;
+  OnCreateSelectChange();
 
-  // select first text input element of dialog for usability
-  SelectField('txtAttachmentname');
+  // Activate the "OK" button.
+  window.parent.SetOkButton(true);
 }
+
 
 function LoadSelection()
 {
-  if (!oLink) return;
+  if (!oLink)
+    return;
 
   if (oLink.getAttribute('title') && oLink.getAttribute('title').StartsWith('attachment:'))
   {
-    GetE('txtAttachmentname').value = decodeUrl(oLink.getAttribute('title').Remove(0, 'attachment:'.length));
+    SetBasePageAttachName(oLink.getAttribute('title').Remove(0, 'attachment:'.length));
   }
 }
 
-//#### Link type selection.
-function SetLinkType(linkType)
+
+// Escape '<', '>', '&' and '"' to avoid XSS issues.
+function escapeHTML(text)
 {
-  ShowE('divLinkTypeAttachment' , (linkType == 'attachment'));
+  return text.replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
 }
 
-//#### Called when user selects Wikipage.
-function OnChangePagename(pagename)
+
+function OnClickListAttachments()
 {
-  GetE("txtPagename").value = pagename;
+  var requested = GetE('requestedPagename').value;
+  GetE('requestedPagename').value = escapeHTML(requested);
 }
 
-//#### Called while the user types the URL.
-function OnUrlChange()
+
+// Try to set selected attachment's name and source page name into the dialog.
+function SetBasePageAttachName(path)
 {
-  var sUrl = GetE('txtUrl').value;
-  var sProtocol = oRegex.UrlOnChangeProtocol.exec(sUrl);
+  path = decodeUrl(path);
 
-  if (sProtocol)
+  var idx = path.lastIndexOf('/'); // Image points to a different page ?
+  var requestedPagename = GetE('requestedPagename').value;
+  var attachmentsPagename = GetE('attachmentsPagename').value;
+  var status = GetE('status').value;
+  var currPicPagename = path.substring(0, idx);
+  var currPicName = path.substring(idx+1, path.length);
+
+  // If there is a request for an attachment located on a different page
+  // then we request a list of attachments for that page.
+  if ((currPicPagename != "") && (currPicPagename != attachmentsPagename))
   {
-    sUrl = sUrl.substr(sProtocol[0].length);
-    GetE('txtUrl').value = sUrl;
+    if (requestedPagename == "")
+    {
+      GetE('requestedPagename').value = currPicPagename;
+      document.DlgAttachmentForm.submit(); // Transmit the form data and reload image dialog.
+      return;
+    }
   }
-  else if (oRegex.UrlOnChangeTestOther.test(sUrl))
+  else
   {
-    GetE('cmbLinkProtocol').value = '';
+    if (idx != -1)
+    {
+      GetE('txtAttachmentPagename').value = currPicPagename;
+      GetE('sctAttachments').value = currPicName;
+    }
+    else
+    {
+      currPicName = path;
+      GetE('txtAttachmentPagename').value = attachmentsPagename;
+      GetE('sctAttachments').value = currPicName;
+    }
+  }
+
+  // Check if the page and the attachment exist.
+  if (status == 0)
+  {
+    if (currPicPagename == requestedPagename)
+    {
+      alert(LanguageString("langPageAttachmentNotFound", requestedPagename, currPicName));
+      AppendDropDownList(LanguageString("langAttachmentNotFoundMarker", currPicName), currPicName);
+    }
+    else
+      alert(LanguageString("langPageNotFound", attachmentsPagename));
+  }
+  else if (GetE('sctAttachments').value != currPicName && (currPicPagename == requestedPagename || requestedPagename == ""))
+  {
+    alert(LanguageString("langAttachmentNotFound", currPicName, attachmentsPagename));
+    AppendDropDownList("Not found: " + currPicName, currPicName);
   }
 }
+
+
+// Append option to drop down list.
+function AppendDropDownList(text, value)
+{
+  // Add missing attachment to drop down list.
+  var optn = document.createElement("OPTION");
+  optn.text = text;
+  optn.value = value;
+  GetE('sctAttachments').options.add(optn);
+  GetE('sctAttachments').value = value;
+}
+
+
+// If the user changes the radio button's states, all unneeded dialog elements
+// will be grayed out here. Also all needed dialog elements will be ungrayed.
+function OnCreateSelectChange()
+{
+  if (!GetE('radioCreateAttachment').checked)
+  {
+    GetE('txtNewAttachmentName').disabled = true;
+    GetE('DlgNewAttachmentName').style.color = "gray";
+    GetE('DlgNewAttachmentInfo').style.color = "gray";
+
+    GetE('DlgAttachmentPage').style.color = "black";
+    GetE('DlgAttachmentList').style.color = "black";
+    GetE('txtAttachmentPagename').disabled = false;
+    GetE('btnListAttachments').disabled = true;
+    GetE('sctAttachments').disabled = false;
+  }
+  else
+  {
+    GetE('txtNewAttachmentName').disabled = false;
+    GetE('DlgNewAttachmentName').style.color = "black";
+    GetE('DlgNewAttachmentInfo').style.color = "black";
+
+    GetE('DlgAttachmentPage').style.color = "gray";
+    GetE('DlgAttachmentList').style.color = "gray";
+    GetE('txtAttachmentPagename').disabled = true;
+    GetE('btnListAttachments').disabled = true;
+    GetE('sctAttachments').disabled = true;
+  }
+}
+
+
+//#### Called while the user types the remote page name.
+function OnAttachmentPagenameChange()
+{
+  GetE('requestedPagename').value = StripWhitespace(escapeHTML(GetE('txtAttachmentPagename').value));
+
+  // If the remote page name was changed by the user, we gray out the drop
+  // down listbox cause the attachments inside don't match with the page name
+  // until the user presses the button.
+  // The button will be ungrayed here so the user can press it to load all
+  // attachments on the remote page.
+  if (GetE('txtAttachmentPagename').value != "")
+  {
+    GetE('DlgAttachmentList').style.color = "gray";
+    GetE('sctAttachments').disabled = true;
+    GetE('btnListAttachments').disabled = false;
+    invalidAttachmentList = true;
+  }
+  else
+  {
+    GetE('DlgAttachmentList').style.color = "gray";
+    GetE('sctAttachments').disabled = true;
+    GetE('btnListAttachments').disabled = true;
+    invalidAttachmentList = true;
+  }
+}
+
+
+// Does the user want to create a new attachment or does he want to select
+// from the drop down list.
+function RadioCreateSelectAttachmentState()
+{
+  if (GetE('radioCreateAttachment').checked)
+    return true;
+  else
+    return false;
+}
+
+
+function StripWhitespace(text)
+{
+  text = text.replace(/^\s*|\s*$/g,'');
+  return text;
+}
+
 
 //#### The OK button was hit.
 function Ok()
 {
-  var sUri;
-  var sText = '';
+  var createAttachment = RadioCreateSelectAttachmentState();
+  var newAttachmentName = StripWhitespace(escapeHTML(GetE('txtNewAttachmentName').value));
+  var attachmentPagename = StripWhitespace(escapeHTML(GetE('txtAttachmentPagename').value));
+  var src = StripWhitespace(escapeHTML(GetE('txtAttachmentPagename').value)); // Image Source page/URL.
+  var destinationPagename = StripWhitespace(escapeHTML(GetE('destinationPagename').value));
+  var attachmentName = StripWhitespace(escapeHTML(GetE('sctAttachments').value)); // Image name.
+  var indexOfAttachmentList = GetE('sctAttachments').selectedIndex;
+  var title = '';
 
-  sUri = GetE('txtAttachmentname').value;
-  if (sUri.length == 0)
+  // Check if the required gui elements are filled or selected.
+  if (!createAttachment)
   {
-    alert(FCKLang.DlnLnkMsgNoUrl);
-    return false;
+    if (attachmentPagename.length == 0)
+    {
+      GetE('txtAttachmentPagename').focus();
+      alert(LanguageString("langAlertMissingPageName"));
+      return false;
+    }
+
+    if (invalidAttachmentList)
+    {
+      alert(LanguageString("langAlertInvalidDropDownList"));
+      return false;
+    }
+
+    if (indexOfAttachmentList == 0)
+    {
+      alert(LanguageString("langAlertMissingAttachment"));
+      return false;
+    }
   }
-  sText = sUri;
-  sUri = encodeUrl(sUri);
+  else
+  {
+    if (newAttachmentName.length == 0)
+    {
+      GetE('txtNewAttachmentName').focus();
+      alert(LanguageString("langAlertMissingNewAttachmentName"));
+      return false;
+    }
+  }
 
-  if (oLink) // Modifying an existent link.
+  if (!createAttachment)
   {
-    oLink.href = sUri;
+    // If attachment is on a different page, than we add a reference to it before
+    // the attachment name (e.g.: remotepagename/attachment.pdf).
+    // But: If you rename the destination's page name, this link won't be
+    // processed by moin and will result in a broken link!
+    if (destinationPagename != src)
+      src += "/" + attachmentName;
+    else
+      src = attachmentName;
   }
-  else   // Creating a new link.
+  else
+    src = newAttachmentName;
+
+  linkText = src;
+  src = encodeUrl(src);
+
+  if (oLink)
   {
-    oLink = oEditor.FCK.CreateLink(sUri)[0];
-    if (! oLink)
+    // Modifying an existent link.
+    oLink.href = src;
+  }
+  else
+  {
+    // Creating a new link.
+    oLink = oEditor.FCK.CreateLink(src)[0];
+    if (!oLink)
     {
       oLink = oEditor.FCK.CreateElement('A');
-      oLink.href = sUri;
-      oLink.appendChild(oEditor.FCK.EditorDocument.createTextNode(sText)); 
+      oLink.href = src;
+      oLink.appendChild(oEditor.FCK.EditorDocument.createTextNode(linkText));
     }
   }
-  
-  SetAttribute(oLink, 'title', 'attachment:' + sUri);
 
+  SetAttribute(oLink, 'title', 'attachment:' + src);
   return true;
 }
 
-function SetUrl(url)
+
+// Create translation string from HTML variable. This variable was created in MoinMoin.
+// string LanguageString(<translationTemplate>, <variable1>, <variable2>, ...)
+// - translationTemplate : sprintf like string (e.g.: "error in %s")
+// - variable1 : this variable replaces the first '%s' in translationTemplate
+// - variable2 : this variable replaces the second '%s' in translationTemplate
+// ...
+// Return value: translated string
+function LanguageString(translationId)
 {
-  document.getElementById('txtUrl').value = url;
-  OnUrlChange();
+  var translationTemplate = GetE(translationId).value;
+
+  switch(arguments.length)
+  {
+    case 1:
+      translatedString = translationTemplate;
+      break;
+    case 2:
+      translatedString = sprintf(translationTemplate, arguments[1]);
+      break;
+    case 3:
+      translatedString = sprintf(translationTemplate, arguments[1], arguments[2]);
+      break;
+    case 4:
+      translatedString = sprintf(translationTemplate, arguments[1], arguments[2], arguments[3]);
+      break;
+    case 5:
+      translatedString = sprintf(translationTemplate, arguments[1], arguments[2], arguments[3], arguments[4]);
+      break;
+    case 6:
+      translatedString = sprintf(translationTemplate, arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
+      break;
+    default:
+      alert("Too much parameters in 'LanguageString'!");
+      translatedString = "Error during translation!";
+      break;
+  }
+
+  return translatedString;
 }
 
+
+/**
+ * sprintf() for JavaScript v.0.4
+ *
+ * Copyright (c) 2007 Alexandru Marasteanu <http://alexei.417.ro/>
+ * Thanks to David Baird (unit test and patch).
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+function str_repeat(i, m) { for (var o = []; m > 0; o[--m] = i); return(o.join('')); }
+
+function sprintf () {
+  var i = 0, a, f = arguments[i++], o = [], m, p, c, x;
+  while (f) {
+    if (m = /^[^\x25]+/.exec(f)) o.push(m[0]);
+    else if (m = /^\x25{2}/.exec(f)) o.push('%');
+    else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
+      if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) throw("Too few arguments.");
+      if (/[^s]/.test(m[7]) && (typeof(a) != 'number'))
+        throw("Expecting number but found " + typeof(a));
+      switch (m[7]) {
+        case 'b': a = a.toString(2); break;
+        case 'c': a = String.fromCharCode(a); break;
+        case 'd': a = parseInt(a); break;
+        case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
+        case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
+        case 'o': a = a.toString(8); break;
+        case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
+        case 'u': a = Math.abs(a); break;
+        case 'x': a = a.toString(16); break;
+        case 'X': a = a.toString(16).toUpperCase(); break;
+      }
+      a = (/[def]/.test(m[7]) && m[2] && a > 0 ? '+' + a : a);
+      c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
+      x = m[5] - String(a).length;
+      p = m[5] ? str_repeat(c, x) : '';
+      o.push(m[4] ? a + p : p + a);
+    }
+    else throw ("Huh ?!");
+    f = f.substring(m[0].length);
+  }
+  return o.join('');
+}
--- a/MoinMoin/web/static/htdocs/applets/moinFCKplugins/moinattachment/fckplugin.js	Sat Nov 21 16:31:36 2009 +0100
+++ b/MoinMoin/web/static/htdocs/applets/moinFCKplugins/moinattachment/fckplugin.js	Sun Nov 22 19:35:15 2009 +0100
@@ -15,13 +15,13 @@
 }
 
 // Register the related command.
-FCKCommands.RegisterCommand('Attachment', new FCKDialogCommand( 'Attachment', FCKLang.DlgLnkWindowTitle, FCKConfig.WikiBasePath + FCKConfig.WikiPage + '?action=fckdialog&dialog=attachment', 400, 330, LinkState, 'CreateAttachment')) ;
+FCKCommands.RegisterCommand('Attachment', new FCKDialogCommand( 'Attachment', "Attachment", FCKConfig.WikiBasePath + FCKConfig.WikiPage + '?action=fckdialog&dialog=attachment', 600, 500, LinkState, 'CreateAttachment')) ;
 
 oAttachmentItem = new FCKToolbarButton('Attachment', FCKLang.AttachmentBtn, null, null, false, true);
 } 
 else
 {
-FCKCommands.RegisterCommand('Attachment', new FCKDialogCommand( 'Attachment', FCKLang.DlgLnkWindowTitle, FCKConfig.WikiBasePath + FCKConfig.WikiPage + '?action=fckdialog&dialog=attachment', 400, 330, FCK.GetNamedCommandState, 'CreateAttachment')) ;
+FCKCommands.RegisterCommand('Attachment', new FCKDialogCommand( 'Attachment', "Attachment", FCKConfig.WikiBasePath + FCKConfig.WikiPage + '?action=fckdialog&dialog=attachment', 600, 500, FCK.GetNamedCommandState, 'CreateAttachment')) ;
 
 oAttachmentItem = new FCKToolbarButton('Attachment', FCKLang.AttachmentBtn, null, null, false, false);
 }

