changeset 5313:37b22f678801

merged Josef's GUI editor attachment dialog improvements
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sat, 28 Nov 2009 13:51:13 +0100
parents a1215ba14417 (current diff) fd6e62d305a6 (diff)
children e005834bbf85
files
diffstat 3 files changed, 253 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/action/fckdialog.py	Sat Nov 28 13:42:41 2009 +0100
+++ b/MoinMoin/action/fckdialog.py	Sat Nov 28 13:51:13 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,51 @@
 </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 + '/'
-    action = scriptname
+    action = request.script_root + "/"
+
+    # 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 = wikiutil.escape(request.values.get("requestedPagename", ""), quote=True)
+    destinationPagename = wikiutil.escape(request.values.get("destinationPagename", request.page.page_name), quote=True)
+
+    attachmentsPagename = requestedPagename or request.page.page_name
+    attachments = _get_files(request, attachmentsPagename)
+    attachments.sort()
+    attachmentList = '''
+        <select id="sctAttachments" size="10" style="width:100%%;visibility:hidden;" onchange="OnAttachmentListChange();">
+        %s
+        </select>
+''' % "\n".join(['<option value="%s">%s</option>' % (wikiutil.escape(attachment, quote=True), wikiutil.escape(attachment, quote=True))
+                 for attachment in attachments])
+
+    # Translation of dialog texts.
+    langAttachmentLocation = _("Attachment location")
+    langPagename = _("Page name")
+    langAttachmentname = _("Attachment name")
+    langListAttachmentsButton = _("Refresh attachment list")
+    langAttachmentList = _("List of attachments")
+
+    if len(attachmentsPagename) > 50:
+        shortenedPagename = "%s ... %s" % (attachmentsPagename[0:25], attachmentsPagename[-25:])
+    else:
+        shortenedPagename = attachmentsPagename
+    langAvailableAttachments = "%s: %s" % (_("Available attachments for page"), shortenedPagename)
+
     request.write('''
 <!--
  * FCKeditor - The text editor for internet
@@ -422,32 +437,64 @@
   <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">
+
+    <div id="divInfo" style="valign=top;">
+    <div id="divLinkTypeAttachment">
+    <fieldset>
+    <legend>%(langAttachmentLocation)s</legend>
+    <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 valign="bottom" style="width:90%%" style="padding-bottom:10px">
+                <span>%(langPagename)s</span><br>
+            </td>
         </tr>
-       </table>
-       </form>
-      </td>
-     </tr>
+        <tr>
+            <td valign="bottom" style="width:100%%" style="padding-bottom:10px;padding-right:10px;">
+                <input id="txtPagename" type="text" onkeyup="OnPagenameChange();" onchange="OnPagenameChange();" style="width:98%%">
+            </td>
+        </tr>
+        <tr>
+            <td valign="bottom" style="width:90%%" style="padding-bottom:10px;">
+                <span>%(langAttachmentname)s</span><br>
+            </td>
+        </tr>
+        <tr valign="bottom">
+            <td valign="bottom" style="width:100%%" style="padding-bottom:10px;padding-right:10px;">
+                <input id="txtAttachmentname" type="text" onkeyup="OnAttachmentnameChange();" onchange="OnPagenameChange();" style="width:98%%"><br>
+            </td>
+        </tr>
     </table>
+    </fieldset>
+    <fieldset>
+    <legend>%(langAvailableAttachments)s</legend>
+    <table cellSpacing="0" cellPadding="0" width="100%%" border="0">
+        <tr>
+            <td valign="bottom" style="width:100%%" style="padding-bottom:10px">
+                <input id="btnListAttachments" type="submit" value="%(langListAttachmentsButton)s">
+            </td>
+        </tr>
+        <tr>
+            <td valign="top" style="padding-top:10px">
+                <label for="sctAttachments">%(langAttachmentList)s</label><br>
+                %(attachmentList)s
+            </td>
+        </tr>
+    </table>
+    </fieldset>
    </div>
   </div>
+   </form>
  </body>
 </html>
 ''' % locals())
 
+
 ##############################################################################
 ### Image dialog
 ##############################################################################
--- a/MoinMoin/web/static/htdocs/applets/moinFCKplugins/moinattachment/fck_attachment.js	Sat Nov 28 13:42:41 2009 +0100
+++ b/MoinMoin/web/static/htdocs/applets/moinFCKplugins/moinattachment/fck_attachment.js	Sat Nov 28 13:51:13 2009 +0100
@@ -18,23 +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'));
-}
-
 //#### Regular Expressions library.
 var oRegex = new Object();
 
@@ -57,105 +46,194 @@
 //#### 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);
-
- // Load the selected link information (if any).
- LoadSelection();
+  // Translate the dialog box texts.
+  oEditor.FCKLanguageManager.TranslatePage(document);
 
- // Show the initial dialog content.
- GetE('divInfo').style.display = '';
+  // Load the selected link information (if any).
+  LoadSelection();
 
- // Activate the "OK" button.
- window.parent.SetOkButton(true);
+  HandleOkButton();
+}
 
-  // select first text input element of dialog for usability
-  SelectField('txtAttachmentname');
-}
 
 function LoadSelection()
 {
-  if (!oLink) return;
+  if (!oLink)
+  {
+    GetE('requestedPagename').value = GetE('attachmentsPagename').value;
+    GetE('txtPagename').value = GetE('attachmentsPagename').value;
+    GetE('sctAttachments').style.visibility = "visible";     
+    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)
+
+// Try to set selected attachment's name and source page name into the dialog.
+function SetBasePageAttachName(path)
 {
-  ShowE('divLinkTypeAttachment' , (linkType == 'attachment'));
-}
+  path = decodeUrl(path);
 
-//#### Called when user selects Wikipage.
-function OnChangePagename(pagename)
-{
-  GetE("txtPagename").value = pagename;
+  var idx = path.lastIndexOf('/'); // Attachment points to a different page ?
+  var requestedPagename = unescapeHTML(GetE('requestedPagename').value);
+  var attachmentsPagename = unescapeHTML(GetE('attachmentsPagename').value);
+  var currPagename = path.substring(0, idx);
+  var currAttachmentname = 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 ((currPagename != "") && (currPagename != attachmentsPagename))
+  {
+    if (requestedPagename == "")
+    {
+      GetE('requestedPagename').value = currPagename;
+      document.DlgAttachmentForm.submit(); // Transmit the form data and reload attachment dialog.
+      return;
+    }
+  }
+  else
+  {
+    GetE('txtAttachmentname').value = currAttachmentname;
+    GetE('sctAttachments').value = currAttachmentname;
+  }
+
+  // Initialize the user interface.
+  GetE('sctAttachments').style.visibility = "visible";
+  GetE('requestedPagename').value = GetE('attachmentsPagename').value;
+  GetE('txtPagename').value = GetE('attachmentsPagename').value;
 }
 
-//#### Called while the user types the URL.
-function OnUrlChange()
-{
-  var sUrl = GetE('txtUrl').value;
-  var sProtocol = oRegex.UrlOnChangeProtocol.exec(sUrl);
 
-  if (sProtocol)
-  {
-    sUrl = sUrl.substr(sProtocol[0].length);
-    GetE('txtUrl').value = sUrl;
-  }
-  else if (oRegex.UrlOnChangeTestOther.test(sUrl))
-  {
-    GetE('cmbLinkProtocol').value = '';
-  }
+//#### Called while the user types the remote page name.
+function OnPagenameChange()
+{
+  GetE('requestedPagename').value = StripWhitespace(GetE('txtPagename').value);
+
+  if(GetE('requestedPagename').value != StripWhitespace(GetE('attachmentsPagename').value))
+    GetE('sctAttachments').disabled = true;
+  else
+    GetE('sctAttachments').disabled = false;
+
+  HandleOkButton();
 }
 
+
+// If the user types in an attachment name in the attachment name edit field,
+// we can check just in time if the name exists on the current page.
+function OnAttachmentnameChange()
+{
+  // Unselect the currently selected listbox item.
+  var idx = GetE('sctAttachments').selectedIndex;
+  if(idx!=-1)
+    GetE('sctAttachments').options[idx].selected = false;
+
+  HandleOkButton();
+}
+
+
+function OnAttachmentListChange()
+{
+  var idx = GetE('sctAttachments').selectedIndex;
+  GetE('txtAttachmentname').value = GetE('sctAttachments').options[idx].value;
+  HandleOkButton();
+}
+
+
+function StripWhitespace(text)
+{
+  text = text.replace(/^\s*|\s*$/g,'');
+  return text;
+}
+
+
+function HandleOkButton()
+{
+  var pageName = StripWhitespace(GetE('txtPagename').value);
+  var attachmentName = StripWhitespace(GetE('txtAttachmentname').value);
+
+  // Activate the "OK" button.
+  if (pageName.length == 0 || attachmentName.length == 0)
+    window.parent.SetOkButton(false);
+  else
+    window.parent.SetOkButton(true);
+}
+
+
+// Escape '<', '>', '&' and '"' to avoid XSS issues.
+function escapeHTML(text)
+{
+  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
+}
+// Unescape '<', '>', '&' and '"' to avoid XSS issues.
+function unescapeHTML(text)
+{
+  return text.replace(/&quot;/g, "\"").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
+}
+
+
+function GetAttachmentURI(pageName, attachmentName)
+{
+  return encodeURI(FCKConfig['WikiBasePath'] + pageName +
+          "?action=AttachFile&do=view&target=" + attachmentName);
+}
+
+
 //#### The OK button was hit.
 function Ok()
 {
-  var sUri;
-  var sText = '';
-
-  sUri = GetE('txtAttachmentname').value;
-  if (sUri.length == 0)
-  {
-    alert(FCKLang.DlnLnkMsgNoUrl);
-    return false;
-  }
-  sText = sUri;
-  sUri = encodeUrl(sUri);
+  var pageName = StripWhitespace(GetE('txtPagename').value); // Attachment's source page/URL.
+  var attachmentName = StripWhitespace(GetE('txtAttachmentname').value);
+  var destinationPagename = StripWhitespace(GetE('destinationPagename').value);
+  var indexOfAttachmentList = GetE('sctAttachments').selectedIndex;
+  var title = '';
+  var fullAttachmentName = '';
 
-  if (oLink) // Modifying an existent link.
-  {
-    oLink.href = sUri;
-  }
-  else   // Creating a new link.
+  // 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 != pageName)
+    fullAttachmentName = pageName + "/" + attachmentName;
+  else
+    fullAttachmentName = attachmentName;
+
+  var linkText = fullAttachmentName;
+  var attachmentURI = GetAttachmentURI(pageName, attachmentName);
+
+  if (oLink)
   {
-    oLink = oEditor.FCK.CreateLink(sUri)[0];
-    if (! oLink)
+    // Modify an existent link.
+    oLink.href = attachmentURI;
+    SetAttribute( oLink, '_fcksavedurl', attachmentURI ) ;
+  }
+  else
+  {
+    // Creating a new link.
+    oLink = oEditor.FCK.CreateLink(fullAttachmentName)[0];
+    if (!oLink)
     {
+      // If no link text is present...
       oLink = oEditor.FCK.CreateElement('A');
-      oLink.href = sUri;
-      oLink.appendChild(oEditor.FCK.EditorDocument.createTextNode(sText)); 
+      oLink.href = attachmentURI;
+      oLink.appendChild(oEditor.FCK.EditorDocument.createTextNode(linkText));
+    }
+    else
+    {
+      // If link text is marked...
+      oLink.href = attachmentURI;
     }
   }
-  
-  SetAttribute(oLink, 'title', 'attachment:' + sUri);
 
+  SetAttribute(oLink, 'title', 'attachment:' + fullAttachmentName);
   return true;
 }
-
-function SetUrl(url)
-{
-  document.getElementById('txtUrl').value = url;
-  OnUrlChange();
-}
-
--- a/MoinMoin/web/static/htdocs/applets/moinFCKplugins/moinattachment/fckplugin.js	Sat Nov 28 13:42:41 2009 +0100
+++ b/MoinMoin/web/static/htdocs/applets/moinFCKplugins/moinattachment/fckplugin.js	Sat Nov 28 13:51:13 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);
 }