source: trunk/www/filemanager/directories/list_directories.jsp @ 4796

Last change on this file since 4796 was 4796, checked in by Nicklas Nordborg, 15 years ago

References #1241: Implement "lazy loading" of the directory tree

We can display the path even on directories where the current user is lacking read permission.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 10.6 KB
Line 
1<%-- $Id: list_directories.jsp 4796 2009-03-02 18:58:58Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) 2006 Jari Hakkinen, Nicklas Nordborg
4
5  This file is part of BASE - BioArray Software Environment.
6  Available at http://base.thep.lu.se/
7
8  BASE is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License
10  as published by the Free Software Foundation; either version 3
11  of the License, or (at your option) any later version.
12
13  BASE is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with BASE. If not, see <http://www.gnu.org/licenses/>.
20  ------------------------------------------------------------------
21
22  @author Nicklas
23  @version 2.0
24--%>
25<%@ page session="false"
26  import="net.sf.basedb.core.SessionControl"
27  import="net.sf.basedb.core.DbControl"
28  import="net.sf.basedb.core.SystemItems"
29  import="net.sf.basedb.core.Item"
30  import="net.sf.basedb.core.ItemContext"
31  import="net.sf.basedb.core.Directory"
32  import="net.sf.basedb.core.Experiment"
33  import="net.sf.basedb.core.User"
34  import="net.sf.basedb.core.ItemQuery"
35  import="net.sf.basedb.core.ItemResultIterator"
36  import="net.sf.basedb.core.Permission"
37  import="net.sf.basedb.core.query.Restrictions"
38  import="net.sf.basedb.core.query.Expressions"
39  import="net.sf.basedb.core.query.Orders"
40  import="net.sf.basedb.core.query.Hql"
41  import="net.sf.basedb.util.FileUtil"
42  import="net.sf.basedb.clients.web.Base"
43  import="net.sf.basedb.clients.web.util.HTML"
44  import="net.sf.basedb.util.Values"
45  import="java.util.Map"
46  import="java.util.Set"
47  import="java.util.HashSet"
48  import="java.util.List"
49%>
50<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
51<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
52<%!
53String generateSubTree(Map<Directory, List<Directory>> tree, Set<Directory> ignore, Directory parent, String ID, String parentId)
54{
55  if (ignore.contains(parent)) return "";
56  ignore.add(parent);
57  StringBuilder sb = new StringBuilder();
58  if (parentId == null) parentId = "dir"+parent.getId();
59  List<Directory> children = tree.get(parent);
60  if (children == null) return "";
61  for (Directory child : children)
62  {
63    if (ignore.contains(child)) continue;
64    String folderIcon = "Folder";
65    if (child.isHomeDirectory())
66    {
67      folderIcon = "UserHome";
68    }
69    else if (child.isRemoved())
70    {
71      folderIcon = "FolderDeleted";
72    }
73    else if (child.getAutoCompress())
74    {
75      folderIcon = "FolderCompressed";
76    }
77    sb.append("var dir").append(child.getId()).append(" = JoustMenu.addLazyChildItem(").append(parentId);
78    sb.append(",'").append(folderIcon).append("'");
79    sb.append(",'").append(HTML.javaScriptEncode(child.getName())).append("'");
80    sb.append(",'directoryOnClick(").append(child.getId()).append(",");
81    sb.append(" \"").append(HTML.javaScriptEncode(child.getPath().toString())).append("\")'");
82    sb.append(",'', 'D").append(child.getId()).append("',");
83    sb.append("'lazyInitSubdir(").append(child.getId()).append(")')\n");
84    sb.append(generateSubTree(tree, ignore, child, ID, null));
85  }
86  return sb.toString();
87}
88%>
89<%
90final Item itemType = Item.DIRECTORY;
91final SessionControl sc = Base.getExistingSessionControl(pageContext, Permission.DENIED, itemType);
92final String ID = sc.getId();
93final DbControl dc = sc.newDbControl();
94final String mode = request.getParameter("mode");
95final String callback = request.getParameter("callback");
96final float scale = Base.getScale(sc);
97final String requestTitle = request.getParameter("title");
98final ItemContext cc = sc.getCurrentContext(itemType);
99int directoryId = cc.getId();
100try
101{
102  final User user = User.getById(dc, sc.getLoggedInUserId());
103  final Directory userHome = user.getHomeDirectory();
104  final boolean readDirectories = sc.hasPermission(Permission.READ, Item.DIRECTORY);
105  final Directory root = Directory.getById(dc, SystemItems.getId(readDirectories ? Directory.ROOT : Directory.HOME)); 
106  Directory current = directoryId != 0 ? Directory.getById(dc, directoryId) : null;
107  if (current == null) current = userHome;
108  if (current == null) current = root;
109 
110  final String rootIcon;
111  final String rootTitle;
112  if (root.isRootDirectory())
113  {
114    rootIcon = "Root";
115    rootTitle = "Root";
116  }
117  else
118  {
119    rootIcon = "Home";
120    rootTitle = "Other users";
121  }
122  Map<Directory, List<Directory>> tree = FileUtil.loadMinimalDirectoryTree(dc, root, userHome, current);
123  Set<Directory> ignore = new HashSet<Directory>();
124  %>
125  <base:page title="<%=requestTitle != null ? requestTitle : ""%>" type="popup">
126  <base:head scripts="newjoust.js,table.js,ajax.js" styles="newjoust.css,toolbar.css">
127  <script language="JavaScript">
128  var isInitialised = false;
129  function initialise()
130  {
131    if (parent && parent.parent && parent.parent.adjustIFrameSize) parent.parent.adjustIFrameSize();
132    IconStore.init();
133    <%
134    // Root entry for the user's Home directory
135    if (userHome != null)
136    {
137      %>
138      var userHome = JoustMenu.addMenuItem(-1, 'Home', 'My home', 'directoryOnClick(<%=userHome.getId()%>, "<%=HTML.javaScriptEncode(userHome.getPath().toString())%>")', '', 'D<%=userHome.getId()%>');
139      JoustMenu.menuItems[userHome].noOutlineIcon = true;
140      JoustMenu.menuItems[userHome].isOpen = true;
141      <%=generateSubTree(tree, ignore, userHome, ID, "userHome")%>
142      <%
143    }
144    // Root entry for entire directory tree
145    %>
146    var root = JoustMenu.addMenuItem(-1, '<%=rootIcon%>', '<%=HTML.javaScriptEncode(rootTitle)%>', 'directoryOnClick(<%=root.getId()%>, "<%=HTML.javaScriptEncode(root.getPath().toString())%>")', '', 'D<%=root.getId()%>');
147    JoustMenu.menuItems[root].noOutlineIcon = true;
148    JoustMenu.menuItems[root].isOpen = true;
149    <%=generateSubTree(tree, ignore, root, ID, "root")%>
150
151    <%
152    // Add 'current' as root entry if we have not seen it before
153    if (!ignore.contains(current))
154    {
155      // but... move up as far as the user has 'read' permission...
156      Directory currentRoot = current;
157      try
158      {
159        while (currentRoot != null && !ignore.contains(currentRoot.getParent()))
160        {
161          currentRoot = currentRoot.getParent();
162        }
163      }
164      catch (Throwable t)
165      {}
166      if (currentRoot == null) currentRoot = current;
167      %>
168      var currentRoot = JoustMenu.addMenuItem(-1, 'Folder', '<%=HTML.javaScriptEncode(currentRoot.getPath().toString())%>', 'directoryOnClick(<%=currentRoot.getId()%>, "<%=HTML.javaScriptEncode(currentRoot.getPath().toString())%>")', '', 'D<%=currentRoot.getId()%>');
169      JoustMenu.menuItems[currentRoot].noOutlineIcon = true;
170      JoustMenu.menuItems[currentRoot].isOpen = true;
171      <%=generateSubTree(tree, ignore, currentRoot, ID, "currentRoot")%>
172      <%
173    }
174    %>
175    JoustMenu.draw('joust');
176    var lastDirectory = JoustMenu.menuItems['D<%=current.getId()%>'];
177    JoustMenu.select(lastDirectory.index);
178    JoustMenu.alwaysSendOnClickToSelected = true;
179    isInitialised = true;
180  }
181 
182  function lazyInitSubdir(directoryId)
183  {
184    var request = Ajax.getXmlHttpRequest();
185    var url = 'ajax.jsp?ID=<%=ID%>&cmd=GetSubdirectories&item_id=' + directoryId;
186    request.open("GET", url, false);
187    // NOTE! 'false' causes code to wait for the response. aka. 'Synchronous AJAX' or SJAX.
188    request.send(null);
189    var response = request.responseText.split('\n');
190   
191    var kv = new Array();
192    var numAdded = 0;
193    var parent = JoustMenu.menuItems['D'+directoryId];
194    for (var i = 0; i < response.length; i++)
195    {
196      var txt = Main.trimString(response[i]);
197      //alert(txt.length+':'+txt);
198      if (txt == 'end')
199      {
200        var id = kv['id'];
201        var folderIcon = 'Folder';
202        if (kv['home'] == 1)
203        {
204          folderIcon = 'UserHome';
205        }
206        else if (kv['removed'] == 1)
207        {
208          folderIcon = 'FolderDeleted';
209        }
210        else if (kv['auto-compress'] == 1)
211        {
212          folderIcon = 'FolderCompressed';
213        }
214        numAdded++;
215        JoustMenu.addLazyChildItem(parent.index, folderIcon, kv['name'], 'directoryOnClick('+id+',\''+kv['path']+'\')', '', 'D'+id, 'lazyInitSubdir('+id+')');
216      }
217      else
218      {
219        var tmp = txt.split(':', 2);
220        kv[tmp[0]] = tmp[1];
221      }
222    }
223    //alert(numAdded);
224    return numAdded > 0;
225  }
226  <%
227  if ("selectonedirectory".equals(mode))
228  {
229    %>
230    var lastDirectoryId;
231    function directoryOnClick(directoryId, path)
232    {
233      var frm = document.forms['directory'];
234      frm.directory_id.value = directoryId;
235      frm.path.value = path;
236      lastDirectoryId = directoryId;
237    }
238    function returnSelected()
239    {
240      var frm = document.forms['directory'];
241      top.window.opener.<%=callback%>(frm.directory_id.value, frm.path.value);
242      top.window.close();
243    }
244    function newDirectory()
245    {
246      Main.viewOrEditItem('<%=ID%>', '<%=itemType.name()%>', 0, true, '&parent_id='+lastDirectoryId);
247    }
248    <%
249  }
250  else
251  {
252    %>
253    function directoryOnClick(directoryId, path)
254    {
255      if (!isInitialised && parent.frames.files.location.href.match('jsp')) return;
256      parent.lastOpenDirectoryId = directoryId;
257      parent.frames.files.location.href = '../files/index.jsp?ID=<%=ID%>&cmd=List&directory_id='+directoryId+'&mode=<%=mode%>';
258      if (window.top.setSelected)
259      {
260        window.top.setSelected('', path);
261      }
262    }
263    <%
264  }
265  %>
266  function refresh()
267  {
268    location.reload();
269  }
270  </script>
271  </base:head>
272 
273  <%
274  if ("selectonedirectory".equals(mode))
275  {
276    %>
277    <base:body onload="initialise()"
278      style="padding-left: 0px; padding-right: 0px;"
279      >
280      <div id="main" class="joust" style="width:100%;">
281        <h3 class="docked"><%=requestTitle == null ? "Select one directory" : requestTitle%></h3>
282        <tbl:toolbar>
283          <tbl:button 
284            image="directory_new.gif" 
285            onclick="newDirectory()" 
286            title="New&hellip;" 
287            tooltip="Create a new directory" 
288          />
289        </tbl:toolbar>
290        <div id="joust" class="boxedbottom" style="height: <%=(int)(scale*340)%>px; overflow:auto; background: #E0E0E0;">
291        </div>
292      </div>
293     
294      <form name="directory">
295      <br>
296      <input type="hidden" name="directory_id" value="">
297      <b><%=requestTitle == null ? "Path" : requestTitle%></b> <input type="text" class="text" readonly name="path" size="40">
298      <p>
299      <table align="center">
300      <tr>
301        <td width="50%"><base:button onclick="returnSelected()" title="Ok" /></td>
302        <td width="50%"><base:button onclick="window.close()" title="Cancel" /></td>
303      </tr>
304      </table>
305      </form>
306    </base:body>
307    <%
308  }
309  else
310  {
311    %>
312    <base:body onload="initialise()" 
313      style="border: 1px solid #999999; border-bottom: 0px; border-right: 0px; padding-left: 0px; padding-right: 0px;" >
314    <div id="main" class="joust" style="width:100%;">
315      <div id="joust" style="overflow: auto;">
316      </div>
317      <div style="width:99%;">
318      <table align="center">
319      <tr>
320        <td><base:button onclick="refresh()" title="Refresh" image="refresh.gif" /></td>
321      </tr>
322      </table>
323      </div>
324    </div>
325    </base:body>
326    <%
327  }
328  %>
329  </base:page>
330  <%
331}
332finally
333{
334  if (dc != null) dc.close();
335}
336%>
Note: See TracBrowser for help on using the repository browser.