]> git.parisson.com Git - pdf.js.git/commitdiff
Switching to the document outline view if the document structure is present
authornotmasteryet <async.processingjs@yahoo.com>
Mon, 22 Aug 2011 02:05:10 +0000 (21:05 -0500)
committernotmasteryet <async.processingjs@yahoo.com>
Mon, 22 Aug 2011 02:05:10 +0000 (21:05 -0500)
pdf.js
web/images/nav-outline.svg [new file with mode: 0644]
web/images/nav-thumbs.svg [new file with mode: 0644]
web/viewer.css
web/viewer.html
web/viewer.js

diff --git a/pdf.js b/pdf.js
index 0ff3381f5d3b9611124c9e87fb1933bd934a647e..0d44822dd229f1f5c20b193bb8e8a1cf7c889c4c 100644 (file)
--- a/pdf.js
+++ b/pdf.js
@@ -3395,6 +3395,9 @@ var Page = (function() {
               TODO('other link types');
               break;
           }
+        } else if (annotation.has('Dest')) {
+          // simple destination link
+          link.dest = annotation.get('Dest').name;
         }
         links.push(link);
       }
@@ -3449,11 +3452,12 @@ var Catalog = (function() {
             var outlineDict = this.xref.fetch(i.obj);
             if (!outlineDict.has('Title'))
               error('Invalid outline item');
-            var dest = outlineDict.get('Dest');
-            if (!dest && outlineDict.get('A')) {
-              var a = this.xref.fetchIfRef(outlineDict.get('A'));
-              dest = a.get('D');
-            }
+            var dest = outlineDict.get('A');
+            if (dest)
+              dest = this.xref.fetchIfRef(dest).get('D');
+            else if (outlineDict.has('Dest'))
+              dest = outlineDict.get('Dest').name;
+
             var outlineItem = {
               dest: dest,
               title: convertIfUnicode(outlineDict.get('Title')),
@@ -3477,7 +3481,8 @@ var Catalog = (function() {
           }
         }
       }
-      return shadow(this, 'documentOutline', root);
+      obj = root.items.length > 0 ? root.items : null;
+      return shadow(this, 'documentOutline', obj);
     },
     get numPages() {
       var obj = this.toplevelPagesDict.get('Count');
@@ -3511,15 +3516,25 @@ var Catalog = (function() {
     },
     get destinations() {
       var xref = this.xref;
+      var dests = {}, nameTreeRef, nameDictionaryRef;
       var obj = this.catDict.get('Names');
-      obj = obj ? xref.fetch(obj) : this.catDict;
-      obj = obj.get('Dests');
-      var dests = {};
-      if (obj) {
+      if (obj)
+        nameTreeRef = xref.fetch(obj).get('Dests');
+      else if(this.catDict.has('Dests'))
+        nameDictionaryRef = this.catDict.get('Dests');
+
+      if (nameDictionaryRef) {
+        // reding simple destination dictionary
+        obj = xref.fetch(nameDictionaryRef);
+        obj.forEach(function(key, value) {
+          dests[key] = xref.fetch(value).get('D');
+        });
+      }
+      if (nameTreeRef) {
         // reading name tree
         var processed = new RefSet();
-        processed.put(obj);
-        var queue = [obj];
+        processed.put(nameTreeRef);
+        var queue = [nameTreeRef];
         while (queue.length > 0) {
           var i, n;
           obj = xref.fetch(queue.shift());
diff --git a/web/images/nav-outline.svg b/web/images/nav-outline.svg
new file mode 100644 (file)
index 0000000..4d4323c
--- /dev/null
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48px"
+   height="48px"
+   id="svg3007"
+   version="1.1"
+   inkscape:version="0.48.1 r9760"
+   sodipodi:docname="nav-outline.svg">
+  <defs
+     id="defs3009">
+    <filter
+       inkscape:collect="always"
+       id="filter5333"
+       x="-0.16623206"
+       width="1.3324641"
+       y="-0.030014125"
+       height="1.0600282">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.47888561"
+         id="feGaussianBlur5335" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="11.945051"
+     inkscape:cx="20.614872"
+     inkscape:cy="23.423899"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1440"
+     inkscape:window-height="773"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata3012">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <rect
+       style="fill:#f0f0f0;fill-rule:evenodd;stroke:#808080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
+       id="rect3783"
+       width="46.16272"
+       height="45.59861"
+       x="1.0341953"
+       y="0.99112236" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect3787"
+       width="2.8205326"
+       height="2.7823999"
+       x="4.2307992"
+       y="4.093708" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5257"
+       width="24.68285"
+       height="1.4102663"
+       x="8.0855274"
+       y="4.657815" />
+    <rect
+       y="8.4185247"
+       x="8.4615984"
+       height="2.7823999"
+       width="2.8205326"
+       id="rect5259"
+       style="fill:#404040;fill-opacity:1;stroke:none" />
+    <rect
+       y="9.0766497"
+       x="12.410344"
+       height="1.4102663"
+       width="30.498053"
+       id="rect5261"
+       style="fill:#404040;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5263"
+       width="2.8205326"
+       height="2.7823999"
+       x="8.4615984"
+       y="13.307448" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5265"
+       width="24.972752"
+       height="1.4102663"
+       x="12.410344"
+       y="13.965573" />
+    <rect
+       y="17.444229"
+       x="4.3248172"
+       height="2.7823999"
+       width="2.8205326"
+       id="rect5267"
+       style="fill:#404040;fill-opacity:1;stroke:none" />
+    <rect
+       y="18.008337"
+       x="8.1795454"
+       height="1.4102663"
+       width="25.101433"
+       id="rect5269"
+       style="fill:#404040;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5271"
+       width="2.8205326"
+       height="2.7823999"
+       x="8.5556164"
+       y="21.769047" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5273"
+       width="28.782515"
+       height="1.4102663"
+       x="12.880433"
+       y="22.427172" />
+    <rect
+       y="26.65797"
+       x="13.475181"
+       height="2.7823999"
+       width="2.8205326"
+       id="rect5275"
+       style="fill:#404040;fill-opacity:1;stroke:none" />
+    <rect
+       y="27.316095"
+       x="17.479"
+       height="1.4102663"
+       width="23.681646"
+       id="rect5277"
+       style="fill:#404040;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5279"
+       width="2.8205326"
+       height="2.7823999"
+       x="8.5130949"
+       y="31.006269" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5281"
+       width="24.557148"
+       height="1.4102663"
+       x="12.592034"
+       y="31.636858" />
+    <rect
+       y="35.464046"
+       x="13.475181"
+       height="2.7823999"
+       width="2.8205326"
+       id="rect5283"
+       style="fill:#404040;fill-opacity:1;stroke:none" />
+    <rect
+       y="36.055695"
+       x="17.744923"
+       height="1.4102663"
+       width="18.577394"
+       id="rect5285"
+       style="fill:#404040;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5287"
+       width="2.8205326"
+       height="2.7823999"
+       x="13.54166"
+       y="40.35297" />
+    <rect
+       style="fill:#404040;fill-opacity:1;stroke:none"
+       id="rect5289"
+       width="23.080858"
+       height="1.4102663"
+       x="17.678442"
+       y="40.944618" />
+  </g>
+</svg>
diff --git a/web/images/nav-thumbs.svg b/web/images/nav-thumbs.svg
new file mode 100644 (file)
index 0000000..8737b8c
--- /dev/null
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48px"
+   height="48px"
+   id="svg3007"
+   version="1.1"
+   inkscape:version="0.48.1 r9760"
+   sodipodi:docname="nav-thumbs.svg">
+  <defs
+     id="defs3009">
+    <filter
+       inkscape:collect="always"
+       id="filter5333"
+       x="-0.16623206"
+       width="1.3324641"
+       y="-0.030014125"
+       height="1.0600282">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.47888561"
+         id="feGaussianBlur5335" />
+    </filter>
+    <filter
+       inkscape:collect="always"
+       id="filter5966">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.3570515"
+         id="feGaussianBlur5968" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="11.945051"
+     inkscape:cx="9.375932"
+     inkscape:cy="24.942259"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1440"
+     inkscape:window-height="773"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata3012">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <rect
+       style="fill:#484848;fill-rule:evenodd;stroke:#808080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
+       id="rect3783"
+       width="46.16272"
+       height="45.59861"
+       x="1.0341953"
+       y="0.99112236" />
+    <rect
+       y="4.7876148"
+       x="14.359808"
+       height="12.764274"
+       width="9.7061672"
+       id="rect5960"
+       style="fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter5966)"
+       transform="matrix(1.0465713,0,0,1.0642851,3.6426579,-2.1141417)" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:none"
+       id="rect5958"
+       width="9.7061672"
+       height="12.764274"
+       x="18.897236"
+       y="3.1920807" />
+    <rect
+       transform="matrix(1.0465713,0,0,1.0642851,3.6426579,13.043433)"
+       style="fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter5966)"
+       id="rect5970"
+       width="9.7061672"
+       height="12.764274"
+       x="14.359808"
+       y="4.7876148" />
+    <rect
+       y="18.349655"
+       x="18.897236"
+       height="12.764274"
+       width="9.7061672"
+       id="rect5972"
+       style="fill:#ffffff;fill-opacity:1;stroke:none" />
+    <rect
+       y="4.7876148"
+       x="14.359808"
+       height="12.764274"
+       width="9.7061672"
+       id="rect5974"
+       style="fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter5966)"
+       transform="matrix(1.0465713,0,0,0.9368834,3.6426579,29.209842)" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:none"
+       id="rect5976"
+       width="9.7061672"
+       height="11.833546"
+       x="18.897236"
+       y="33.906113" />
+    <rect
+       y="4.905829"
+       x="19.960924"
+       height="0.66480595"
+       width="7.7117486"
+       id="rect5995"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6177"
+       width="3.6219761"
+       height="0.66480595"
+       x="19.960924"
+       y="6.0340419" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6179"
+       width="7.7117486"
+       height="0.66480595"
+       x="19.960924"
+       y="7.2562728" />
+    <rect
+       y="8.3844862"
+       x="19.960924"
+       height="0.66480595"
+       width="5.6903667"
+       id="rect6181"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       y="9.7007341"
+       x="19.960924"
+       height="0.66480595"
+       width="7.7117486"
+       id="rect6183"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6185"
+       width="7.7117486"
+       height="0.66480595"
+       x="19.960924"
+       y="10.828948" />
+    <rect
+       y="12.051179"
+       x="19.960924"
+       height="0.66480595"
+       width="7.7117486"
+       id="rect6187"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       y="14.213587"
+       x="23.204536"
+       height="0.66480595"
+       width="1.2245234"
+       id="rect6189"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6209"
+       width="7.7117486"
+       height="0.66480595"
+       x="19.772888"
+       y="19.854652" />
+    <rect
+       y="39.08128"
+       x="19.913914"
+       height="0.66480595"
+       width="3.6219761"
+       id="rect6211"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       y="22.205095"
+       x="19.772888"
+       height="0.66480595"
+       width="6.6305442"
+       id="rect6213"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6215"
+       width="7.7587576"
+       height="0.66480595"
+       x="19.866905"
+       y="37.859051" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6217"
+       width="7.7117486"
+       height="0.66480595"
+       x="19.772888"
+       y="21.029873" />
+    <rect
+       y="25.777771"
+       x="19.772888"
+       height="0.66480595"
+       width="7.7117486"
+       id="rect6219"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6221"
+       width="7.7117486"
+       height="0.66480595"
+       x="19.772888"
+       y="27.000002" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6223"
+       width="1.2245234"
+       height="0.66480595"
+       x="23.204536"
+       y="28.974375" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6225"
+       width="3.6219761"
+       height="0.66480595"
+       x="19.960922"
+       y="42.983021" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6227"
+       width="7.7117486"
+       height="0.66480595"
+       x="19.913914"
+       y="36.777847" />
+    <rect
+       y="35.602627"
+       x="19.913914"
+       height="0.66480595"
+       width="7.7117486"
+       id="rect6231"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#808080;fill-opacity:1;stroke:none"
+       id="rect6233"
+       width="7.7117486"
+       height="0.66480595"
+       x="19.913914"
+       y="40.350525" />
+    <rect
+       y="41.572754"
+       x="19.913914"
+       height="0.66480595"
+       width="7.7117486"
+       id="rect6235"
+       style="fill:#808080;fill-opacity:1;stroke:none" />
+    <rect
+       style="fill:#0000e6;fill-opacity:0.44444448;stroke:none"
+       id="rect6237"
+       width="3.5256658"
+       height="1.927364"
+       x="22.077036"
+       y="23.367346" />
+  </g>
+</svg>
index 54f648adb1ba98d92b8bb0e1b6e4fd0c35b11e2b..e18d9681e35b74972a12ff056addd6320f7d4a96 100644 (file)
@@ -60,10 +60,10 @@ span#info {
 /* === Sidebar === */
 #sidebar {
   position: fixed;
-  width: 200px;
+  width: 350px;
   top: 62px;
   bottom: 18px;
-  left: -140px;
+  left: -290px;
   transition: left 0.25s ease-in-out 1s;
   -moz-transition: left 0.25s ease-in-out 1s;
   -webkit-transition: left 0.25s ease-in-out 1s;
@@ -78,7 +78,7 @@ span#info {
 
 #sidebarBox {
   background-color: rgba(0, 0, 0, 0.7);
-  width: 150px;
+  width: 300px;
   height: 100%;
   border-top-right-radius: 8px;
   border-bottom-right-radius: 8px;
@@ -98,14 +98,73 @@ span#info {
   top: 10px;
   bottom: 10px;
   left: 10px;
-  width: 130px;
+  width: 280px;
 }
 
 .thumbnail {
   width: 104px;
   height: 134px;
   background-color: white;
-  margin: 5px;
+  margin-top: 5px;
+  margin-bottom: 5px;
+  margin-left:auto;
+  margin-right:auto;
+}
+
+#outlineScrollView {
+  position: absolute;
+  background-color: #fff;
+  overflow: auto;
+  top: 10px;
+  bottom: 10px;
+  left: 10px;
+  width: 280px;
+}
+
+#outlineView {
+  padding-top: 4px;
+  padding-bottom: 100px;
+  padding-left: 6px;
+  padding-right: 6px;
+  font-size: smaller;
+}
+
+.outlineItem > .outlineItems {
+  margin-left: 20px;
+}
+
+.outlineItem > a {
+  text-decoration: none;
+  color: black;
+}
+
+.outlineItem > a:hover {
+  background: #ff0;
+  box-shadow: 0px 2px 10px #ff0;
+}
+
+#sidebarControls {
+  position:absolute;
+  width: 120px;
+  height: 32px;
+  left: 15px;
+  bottom: 35px;
+}
+
+#sidebarControls > button {
+  box-shadow: 0px 4px 10px #000;
+  -moz-box-shadow: 0px 4px 10px #000;
+  -webkit-box-shadow: 0px 4px 10px #000;
+}
+
+#sidebarControls > button[disabled] > img {
+  opacity: 0.5;
+}
+
+#sidebarControls > button[data-selected] {
+  box-shadow: 0px 4px 10px #ff0;
+  -moz-box-shadow: 0px 4px 10px #ff0;
+  -webkit-box-shadow: 0px 4px 10px #ff0;
 }
 
 /* === Content view === */
@@ -128,3 +187,10 @@ canvas {
   padding: 8px 0px;
 }
 
+#sidebarView canvas:hover {
+  background: #ff0;
+  box-shadow: 0px 2px 10px #ff0;
+  -moz-box-shadow: 0px 2px 10px #ff0;
+  -webkit-box-shadow: 0px 2px 10px #ff0;
+}
+
index 285dadb015deda9adb3afad35bbd0bdf9ffb02e6..6232ce4b33f41f5dc5431c8d9148c5e773c69959 100644 (file)
         <div id="sidebarScrollView">
           <div id="sidebarView"></div>
         </div>
+        <div id="outlineScrollView" style="display:none">
+          <div id="outlineView"></div>
+        </div>
+        <div id="sidebarControls">
+          <button id="thumbsSwitch" onclick="PDFView.switchSidebarView('thumbs')" data-selected>
+            <img src="images/nav-thumbs.svg" align="top" height="32" />
+          </button>
+          <button id="outlineSwitch" onclick="PDFView.switchSidebarView('outline')" disabled>
+            <img src="images/nav-outline.svg" align="top" height="32" />
+          </button>
+        </div>
      </div>
     </div>
 
index 8fe011b29f4fe48026bc13a79eccfd572a9b1be3..95a32128cdb0e825c6dafd40755ad3fb974f38a4 100644 (file)
@@ -128,6 +128,33 @@ var PDFView = {
     this.page = parseInt(document.location.hash.substring(1)) || 1;
     this.pagesRefMap = pagesRefMap;
     this.destinations = pdf.catalog.destinations;
+    if (pdf.catalog.documentOutline) {
+      this.outline = new DocumentOutlineView(pdf.catalog.documentOutline);
+      var outlineSwitchButton = document.getElementById('outlineSwitch');
+      outlineSwitchButton.removeAttribute('disabled');
+      this.switchSidebarView('outline');
+    }
+  },
+
+  switchSidebarView: function(view) {
+    var thumbsScrollView = document.getElementById('sidebarScrollView');
+    var outlineScrollView = document.getElementById('outlineScrollView');
+    var thumbsSwitchButton = document.getElementById('thumbsSwitch');
+    var outlineSwitchButton = document.getElementById('outlineSwitch');
+    switch(view) {
+      case 'thumbs':
+        thumbsScrollView.style.display = 'block';
+        outlineScrollView.style.display = 'none';
+        thumbsSwitchButton.setAttribute('data-selected', true);
+        outlineSwitchButton.removeAttribute('data-selected');
+        break;
+      case 'outline':
+        thumbsScrollView.style.display = 'none';
+        outlineScrollView.style.display = 'block';
+        thumbsSwitchButton.removeAttribute('data-selected');
+        outlineSwitchButton.setAttribute('data-selected', true);
+        break;
+    }
   },
 
   getVisiblePages: function() {
@@ -289,6 +316,42 @@ var ThumbnailView = function(container, page) {
   };
 };
 
+var DocumentOutlineView = function(outline) {
+  var outlineView = document.getElementById('outlineView');
+
+  function bindItemLink(domObj, item) {
+    domObj.href = '';
+    domObj.onclick = function(e) {
+      PDFView.navigateTo(item.dest);
+      return false;
+    };
+  }
+
+  var queue = [{parent: outlineView, items: outline}];
+  while (queue.length > 0) {
+    var levelData = queue.shift();
+    var i, n = levelData.items.length;
+    for (i = 0; i < n; i++) {
+      var item = levelData.items[i];
+      var div = document.createElement('div');
+      div.className = 'outlineItem';
+      var a = document.createElement('a');
+      bindItemLink(a, item);
+      a.textContent = item.title;
+      div.appendChild(a);
+
+      if (item.items.length > 0) {
+        var itemsDiv = document.createElement('div');
+        itemsDiv.className = 'outlineItems';
+        div.appendChild(itemsDiv);
+        queue.push({parent: itemsDiv, items: item.items});
+      }
+
+      levelData.parent.appendChild(div);
+    }
+  }
+};
+
 window.addEventListener('load', function(evt) {
   var params = document.location.search.substring(1).split('&');
   for (var i = 0; i < params.length; i++) {