Index: css/docuviewer.css
===================================================================
--- css/docuviewer.css	(revision 597)
+++ css/docuviewer.css	(revision 607)
@@ -173,4 +173,7 @@
     color: black;
 }
+div.tocbody table.thumbs a.outside {
+    font-weight: normal;
+}
 
 div.tocbody table.concordance {
Index: documentViewer.py
===================================================================
--- documentViewer.py	(revision 602)
+++ documentViewer.py	(revision 607)
@@ -161,5 +161,5 @@
             #templateFolder._setObject('zogilib',zogilib)
         except Exception, e:
-            logging.error("Unable to create zogiLib for zogilib: "+str(e))
+            logging.error("Unable to create zogiLib for 'zogilib': "+str(e))
             
         try:
@@ -638,4 +638,8 @@
                 # replace with numTextPages (text-only?)
                 docinfo['numPages'] = docinfo['numTextPages']
+                
+        # min and max page no
+        docinfo['minPageNo'] = docinfo.get('minPageNo', 1)
+        docinfo['maxPageNo'] = docinfo.get('maxPageNo', docinfo['numPages'])
 
         # normalize path
@@ -684,8 +688,24 @@
         imageDir = getMDText(texttool.get('image', None))
         docPath = getMDText(docinfo.get('documentPath', None))
-        if imageDir and docPath:
-            imageDir = os.path.join(docPath, imageDir)
-            imageDir = imageDir.replace('/mpiwg/online', '', 1)
-            docinfo['imagePath'] = imageDir
+        if imageDir:
+            if imageDir.startswith('/'):
+                # absolute path
+                imageDir = imageDir.replace('/mpiwg/online', '', 1)
+                docinfo['imagePath'] = imageDir
+                
+            elif docPath:
+                # relative path
+                imageDir = os.path.join(docPath, imageDir)
+                imageDir = imageDir.replace('/mpiwg/online', '', 1)
+                docinfo['imagePath'] = imageDir
+                
+        # start and end page (for subdocuments of other documents)
+        imgStartNo = getMDText(texttool.get('image-start-no', None))            
+        minPageNo = getInt(imgStartNo, 1)
+        docinfo['minPageNo'] = minPageNo
+
+        imgEndNo = getMDText(texttool.get('image-end-no', None))
+        if imgEndNo:
+            docinfo['maxPageNo'] = getInt(imgEndNo)
         
         # old style text URL
@@ -725,5 +745,5 @@
             
         # number of title page (default 1)
-        docinfo['titlePage'] = getMDText(texttool.get('title-scan-no', 1))
+        docinfo['titlePage'] = getMDText(texttool.get('title-scan-no', minPageNo))
             
         # old presentation stuff
@@ -865,4 +885,6 @@
         pageinfo['tocMode'] = tocMode
 
+        minPageNo = docinfo.get('minPageNo', 1)
+
         # pf takes precedence over pn
         if pf:
@@ -873,5 +895,5 @@
             self.REQUEST.form['pn'] = pn
         else:
-            pn = getInt(pn, 1)
+            pn = getInt(pn, minPageNo)
             pf = getPfForPn(docinfo, pn)
             pageinfo['pf'] = pf
@@ -884,15 +906,20 @@
         grpsize = cols * rows
         pageinfo['groupsize'] = grpsize
-        # is start is empty use one around pn
-        start = getInt(start, default=(math.ceil(float(pn)/float(grpsize))*grpsize-(grpsize-1)))
-        # int(current / grpsize) * grpsize +1))
+        # if start is empty use one around pn
+        grouppn = math.ceil(float(pn)/float(grpsize))*grpsize-(grpsize-1)
+        # but not smaller than minPageNo
+        start = getInt(start, max(grouppn, minPageNo))
         pageinfo['start'] = start
         # get number of pages
-        np = int(docinfo.get('numPages', 0))
-        if np == 0:
+        numPages = int(docinfo.get('numPages', 0))
+        if numPages == 0:
             # try numTextPages
-            np = docinfo.get('numTextPages', 0)
-            if np != 0:
-                docinfo['numPages'] = np
+            numPages = docinfo.get('numTextPages', 0)
+            if numPages != 0:
+                docinfo['numPages'] = numPages
+
+        maxPageNo = docinfo.get('maxPageNo', numPages)
+        logging.debug("minPageNo=%s maxPageNo=%s start=%s numPages=%s"%(minPageNo,maxPageNo,start,numPages))
+        np = maxPageNo
 
         # cache table of contents
@@ -907,5 +934,5 @@
         pageZero = (cols == 2 and (pageFlowLtr != oddScanLeft))
         pageinfo['pageZero'] = pageZero
-        pageinfo['pageBatch'] = self.getPageBatch(start=start, rows=rows, cols=cols, pageFlowLtr=pageFlowLtr, pageZero=pageZero, minIdx=1, maxIdx=np)
+        pageinfo['pageBatch'] = self.getPageBatch(start=start, rows=rows, cols=cols, pageFlowLtr=pageFlowLtr, pageZero=pageZero, minIdx=minPageNo, maxIdx=np)
         # more page parameters
         pageinfo['characterNormalization'] = self.REQUEST.get('characterNormalization','reg')
@@ -939,4 +966,5 @@
     def getPageBatch(self, start=1, rows=10, cols=2, pageFlowLtr=True, pageZero=False, minIdx=1, maxIdx=0):
         """returns dict with array of page information for one screenfull of thumbnails"""
+        logging.debug("getPageBatch start=%s minIdx=%s maxIdx=%s"%(start,minIdx,maxIdx))
         batch = {}
         grpsize = rows * cols
@@ -944,11 +972,12 @@
             maxIdx = start + grpsize
 
-        nb = int(math.ceil(maxIdx / float(grpsize)))
+        np = maxIdx - minIdx + 1
+        nb = int(math.ceil(np / float(grpsize)))
         # list of all batch start and end points
         batches = []
         if pageZero:
-            ofs = 0
-        else:
-            ofs = 1
+            ofs = minIdx - 1
+        else:
+            ofs = minIdx
             
         for i in range(nb):
@@ -960,7 +989,7 @@
 
         pages = []
-        if pageZero and start == 1:
+        if pageZero and start == minIdx:
             # correct beginning
-            idx = 0
+            idx = minIdx - 1
         else:
             idx = start
@@ -982,6 +1011,6 @@
             pages.append(row)
             
-        if start > 1:
-            batch['prevStart'] = max(start - grpsize, 1)
+        if start > minIdx:
+            batch['prevStart'] = max(start - grpsize, minIdx)
         else:
             batch['prevStart'] = None
Index: version.txt
===================================================================
--- version.txt	(revision 591)
+++ version.txt	(revision 607)
@@ -1,1 +1,1 @@
-DocumentViewer 2.2.9
+DocumentViewer 2.2.10
Index: zpt/viewer/common_template.zpt
===================================================================
--- zpt/viewer/common_template.zpt	(revision 594)
+++ zpt/viewer/common_template.zpt	(revision 607)
@@ -45,7 +45,7 @@
   <!-- page ruler with previous/next page buttons -->
   <metal:block metal:define-macro="page_ruler"
-    tal:define="
-              prev python:test(pn>1,pn-1,None); next python:test(pn<numPages,pn+1,None);
-              first python:test(pn>1,1,None); last python:test(pn<numPages,numPages,None);
+    tal:define="minPageNo docinfo/minPageNo; maxPageNo docinfo/maxPageNo;
+              prev python:test(pn>minPageNo,pn-1,None); next python:test(pn<maxPageNo,pn+1,None);
+              first python:test(pn>minPageNo,minPageNo,None); last python:test(pn<maxPageNo,maxPageNo,None);
               left python:test(flowLtr,prev,next); right python:test(flowLtr,next,prev);
               leftest python:test(flowLtr,first,last); rightest python:test(flowLtr,last,first);">
@@ -90,6 +90,6 @@
     <form class="autosubmit" tal:attributes="action viewerUrl">
       <input type="hidden" tal:define="params python:here.getParams('start',None)" tal:repeat="param params"
-        tal:attributes="name param; value python:params[param]" /><span class="ruler-main"><a tal:condition="left"
-        tal:attributes="href python:here.getLink('start',left)">&lt;</a> <span tal:condition="not:left">&lt;</span> <select
+        tal:attributes="name param; value python:params[param]" /><span class="ruler-main"><a tal:omit-tag="not:left"
+        tal:attributes="href python:here.getLink('start',left)">&lt;</a> <select
         class="autosubmit" name="start" tal:define="ofs python:test(pageinfo['pageZero'],0,1)">
           <tal:block>
@@ -98,6 +98,6 @@
             <option tal:condition="python:start>pageBatch['last']" selected="selected" value="1">[out of range]</option>
           </tal:block>
-      </select> <input type="submit" value="Go" /> <a tal:condition="right" tal:attributes="href python:here.getLink('start',right)">&gt;</a>
-        <span tal:condition="not:right">&gt;</span></span>
+      </select> <input type="submit" value="Go" /> <a tal:omit-tag="not:right" tal:attributes="href python:here.getLink('start',right)">&gt;</a>
+      </span>
     </form>
   </metal:block>
Index: zpt/viewer/toc_thumbs.zpt
===================================================================
--- zpt/viewer/toc_thumbs.zpt	(revision 594)
+++ zpt/viewer/toc_thumbs.zpt	(revision 607)
@@ -11,4 +11,6 @@
     <div class="tocbody thumbs"
       tal:define="start pageinfo/start;
+                minPageNo docinfo/minPageNo;
+                maxPageNo docinfo/maxPageNo;
                 grpsize pageinfo/groupsize;
                 numgroups pageinfo/numgroups;
@@ -26,5 +28,7 @@
           <tr tal:repeat="row pageBatch/pages">
             <td tal:repeat="thumb row" tal:attributes="class python:here.getStyle(thumb['idx'],pn,'thumb')"><a
-              tal:define="idx thumb/idx" tal:condition="idx" tal:attributes="href python:here.getLink('pn',idx)"> <img
+              tal:define="idx thumb/idx" tal:condition="idx"
+              tal:attributes="href python:here.getLink('pn',idx); class python:test(idx<minPageNo or idx>maxPageNo, 'outside')"><img
+                tal:condition="python:docinfo.get('imageURL',None) or exists('template/text.png')"
                 tal:attributes="src python:test(docinfo.get('imageURL',None),here.getScalerUrl(pn=idx,dw=100,dh=100,docinfo=docinfo),'template/text.png');
                                 alt idx;" /><br />
Index: zpt/viewer/viewer_thumbs.zpt
===================================================================
--- zpt/viewer/viewer_thumbs.zpt	(revision 594)
+++ zpt/viewer/viewer_thumbs.zpt	(revision 607)
@@ -27,9 +27,11 @@
     tal:define="pn pageinfo/pn;
                 start pageinfo/start;
+                minPageNo docinfo/minPageNo;
+                maxPageNo docinfo/maxPageNo;
                 thumbRows python:int(request.get('thumbRows', 10));
                 thumbCols python:int(request.get('thumbCols', 12));
                 thumbSize python:int(request.get('thumbSize', 100));
                 flowLtr python:docinfo.get('pageFlow','ltr')!='rtl';
-                pageBatch python:here.getPageBatch(start=start, rows=thumbRows, cols=thumbCols, pageFlowLtr=flowLtr, maxIdx=numPages);
+                pageBatch python:here.getPageBatch(start=start, rows=thumbRows, cols=thumbCols, pageFlowLtr=flowLtr, minIdx=minPageNo, maxIdx=maxPageNo);
                 pageNumbers docinfo/pageNumbers | nothing;
                 left python:test(flowLtr,pageBatch['prevStart'],pageBatch['nextStart']);
