1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/extensions/pdfjs/content/web/debugger.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,629 @@ 1.4 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ 1.6 +/* Copyright 2012 Mozilla Foundation 1.7 + * 1.8 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.9 + * you may not use this file except in compliance with the License. 1.10 + * You may obtain a copy of the License at 1.11 + * 1.12 + * http://www.apache.org/licenses/LICENSE-2.0 1.13 + * 1.14 + * Unless required by applicable law or agreed to in writing, software 1.15 + * distributed under the License is distributed on an "AS IS" BASIS, 1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.17 + * See the License for the specific language governing permissions and 1.18 + * limitations under the License. 1.19 + */ 1.20 +/* globals PDFJS */ 1.21 + 1.22 +'use strict'; 1.23 + 1.24 +var FontInspector = (function FontInspectorClosure() { 1.25 + var fonts; 1.26 + var active = false; 1.27 + var fontAttribute = 'data-font-name'; 1.28 + function removeSelection() { 1.29 + var divs = document.querySelectorAll('div[' + fontAttribute + ']'); 1.30 + for (var i = 0, ii = divs.length; i < ii; ++i) { 1.31 + var div = divs[i]; 1.32 + div.className = ''; 1.33 + } 1.34 + } 1.35 + function resetSelection() { 1.36 + var divs = document.querySelectorAll('div[' + fontAttribute + ']'); 1.37 + for (var i = 0, ii = divs.length; i < ii; ++i) { 1.38 + var div = divs[i]; 1.39 + div.className = 'debuggerHideText'; 1.40 + } 1.41 + } 1.42 + function selectFont(fontName, show) { 1.43 + var divs = document.querySelectorAll('div[' + fontAttribute + '=' + 1.44 + fontName + ']'); 1.45 + for (var i = 0, ii = divs.length; i < ii; ++i) { 1.46 + var div = divs[i]; 1.47 + div.className = show ? 'debuggerShowText' : 'debuggerHideText'; 1.48 + } 1.49 + } 1.50 + function textLayerClick(e) { 1.51 + if (!e.target.dataset.fontName || 1.52 + e.target.tagName.toUpperCase() !== 'DIV') { 1.53 + return; 1.54 + } 1.55 + var fontName = e.target.dataset.fontName; 1.56 + var selects = document.getElementsByTagName('input'); 1.57 + for (var i = 0; i < selects.length; ++i) { 1.58 + var select = selects[i]; 1.59 + if (select.dataset.fontName != fontName) { 1.60 + continue; 1.61 + } 1.62 + select.checked = !select.checked; 1.63 + selectFont(fontName, select.checked); 1.64 + select.scrollIntoView(); 1.65 + } 1.66 + } 1.67 + return { 1.68 + // Properties/functions needed by PDFBug. 1.69 + id: 'FontInspector', 1.70 + name: 'Font Inspector', 1.71 + panel: null, 1.72 + manager: null, 1.73 + init: function init() { 1.74 + var panel = this.panel; 1.75 + panel.setAttribute('style', 'padding: 5px;'); 1.76 + var tmp = document.createElement('button'); 1.77 + tmp.addEventListener('click', resetSelection); 1.78 + tmp.textContent = 'Refresh'; 1.79 + panel.appendChild(tmp); 1.80 + 1.81 + fonts = document.createElement('div'); 1.82 + panel.appendChild(fonts); 1.83 + }, 1.84 + cleanup: function cleanup() { 1.85 + fonts.textContent = ''; 1.86 + }, 1.87 + enabled: false, 1.88 + get active() { 1.89 + return active; 1.90 + }, 1.91 + set active(value) { 1.92 + active = value; 1.93 + if (active) { 1.94 + document.body.addEventListener('click', textLayerClick, true); 1.95 + resetSelection(); 1.96 + } else { 1.97 + document.body.removeEventListener('click', textLayerClick, true); 1.98 + removeSelection(); 1.99 + } 1.100 + }, 1.101 + // FontInspector specific functions. 1.102 + fontAdded: function fontAdded(fontObj, url) { 1.103 + function properties(obj, list) { 1.104 + var moreInfo = document.createElement('table'); 1.105 + for (var i = 0; i < list.length; i++) { 1.106 + var tr = document.createElement('tr'); 1.107 + var td1 = document.createElement('td'); 1.108 + td1.textContent = list[i]; 1.109 + tr.appendChild(td1); 1.110 + var td2 = document.createElement('td'); 1.111 + td2.textContent = obj[list[i]].toString(); 1.112 + tr.appendChild(td2); 1.113 + moreInfo.appendChild(tr); 1.114 + } 1.115 + return moreInfo; 1.116 + } 1.117 + var moreInfo = properties(fontObj, ['name', 'type']); 1.118 + var m = /url\(['"]?([^\)"']+)/.exec(url); 1.119 + var fontName = fontObj.loadedName; 1.120 + var font = document.createElement('div'); 1.121 + var name = document.createElement('span'); 1.122 + name.textContent = fontName; 1.123 + var download = document.createElement('a'); 1.124 + download.href = m[1]; 1.125 + download.textContent = 'Download'; 1.126 + var logIt = document.createElement('a'); 1.127 + logIt.href = ''; 1.128 + logIt.textContent = 'Log'; 1.129 + logIt.addEventListener('click', function(event) { 1.130 + event.preventDefault(); 1.131 + console.log(fontObj); 1.132 + }); 1.133 + var select = document.createElement('input'); 1.134 + select.setAttribute('type', 'checkbox'); 1.135 + select.dataset.fontName = fontName; 1.136 + select.addEventListener('click', (function(select, fontName) { 1.137 + return (function() { 1.138 + selectFont(fontName, select.checked); 1.139 + }); 1.140 + })(select, fontName)); 1.141 + font.appendChild(select); 1.142 + font.appendChild(name); 1.143 + font.appendChild(document.createTextNode(' ')); 1.144 + font.appendChild(download); 1.145 + font.appendChild(document.createTextNode(' ')); 1.146 + font.appendChild(logIt); 1.147 + font.appendChild(moreInfo); 1.148 + fonts.appendChild(font); 1.149 + // Somewhat of a hack, should probably add a hook for when the text layer 1.150 + // is done rendering. 1.151 + setTimeout(function() { 1.152 + if (this.active) { 1.153 + resetSelection(); 1.154 + } 1.155 + }.bind(this), 2000); 1.156 + } 1.157 + }; 1.158 +})(); 1.159 + 1.160 +// Manages all the page steppers. 1.161 +var StepperManager = (function StepperManagerClosure() { 1.162 + var steppers = []; 1.163 + var stepperDiv = null; 1.164 + var stepperControls = null; 1.165 + var stepperChooser = null; 1.166 + var breakPoints = {}; 1.167 + return { 1.168 + // Properties/functions needed by PDFBug. 1.169 + id: 'Stepper', 1.170 + name: 'Stepper', 1.171 + panel: null, 1.172 + manager: null, 1.173 + init: function init() { 1.174 + var self = this; 1.175 + this.panel.setAttribute('style', 'padding: 5px;'); 1.176 + stepperControls = document.createElement('div'); 1.177 + stepperChooser = document.createElement('select'); 1.178 + stepperChooser.addEventListener('change', function(event) { 1.179 + self.selectStepper(this.value); 1.180 + }); 1.181 + stepperControls.appendChild(stepperChooser); 1.182 + stepperDiv = document.createElement('div'); 1.183 + this.panel.appendChild(stepperControls); 1.184 + this.panel.appendChild(stepperDiv); 1.185 + if (sessionStorage.getItem('pdfjsBreakPoints')) { 1.186 + breakPoints = JSON.parse(sessionStorage.getItem('pdfjsBreakPoints')); 1.187 + } 1.188 + }, 1.189 + cleanup: function cleanup() { 1.190 + stepperChooser.textContent = ''; 1.191 + stepperDiv.textContent = ''; 1.192 + steppers = []; 1.193 + }, 1.194 + enabled: false, 1.195 + active: false, 1.196 + // Stepper specific functions. 1.197 + create: function create(pageIndex) { 1.198 + var debug = document.createElement('div'); 1.199 + debug.id = 'stepper' + pageIndex; 1.200 + debug.setAttribute('hidden', true); 1.201 + debug.className = 'stepper'; 1.202 + stepperDiv.appendChild(debug); 1.203 + var b = document.createElement('option'); 1.204 + b.textContent = 'Page ' + (pageIndex + 1); 1.205 + b.value = pageIndex; 1.206 + stepperChooser.appendChild(b); 1.207 + var initBreakPoints = breakPoints[pageIndex] || []; 1.208 + var stepper = new Stepper(debug, pageIndex, initBreakPoints); 1.209 + steppers.push(stepper); 1.210 + if (steppers.length === 1) { 1.211 + this.selectStepper(pageIndex, false); 1.212 + } 1.213 + return stepper; 1.214 + }, 1.215 + selectStepper: function selectStepper(pageIndex, selectPanel) { 1.216 + var i; 1.217 + if (selectPanel) { 1.218 + this.manager.selectPanel(this); 1.219 + } 1.220 + for (i = 0; i < steppers.length; ++i) { 1.221 + var stepper = steppers[i]; 1.222 + if (stepper.pageIndex == pageIndex) { 1.223 + stepper.panel.removeAttribute('hidden'); 1.224 + } else { 1.225 + stepper.panel.setAttribute('hidden', true); 1.226 + } 1.227 + } 1.228 + var options = stepperChooser.options; 1.229 + for (i = 0; i < options.length; ++i) { 1.230 + var option = options[i]; 1.231 + option.selected = option.value == pageIndex; 1.232 + } 1.233 + }, 1.234 + saveBreakPoints: function saveBreakPoints(pageIndex, bps) { 1.235 + breakPoints[pageIndex] = bps; 1.236 + sessionStorage.setItem('pdfjsBreakPoints', JSON.stringify(breakPoints)); 1.237 + } 1.238 + }; 1.239 +})(); 1.240 + 1.241 +// The stepper for each page's IRQueue. 1.242 +var Stepper = (function StepperClosure() { 1.243 + // Shorter way to create element and optionally set textContent. 1.244 + function c(tag, textContent) { 1.245 + var d = document.createElement(tag); 1.246 + if (textContent) { 1.247 + d.textContent = textContent; 1.248 + } 1.249 + return d; 1.250 + } 1.251 + 1.252 + function glyphsToString(glyphs) { 1.253 + var out = ''; 1.254 + for (var i = 0; i < glyphs.length; i++) { 1.255 + if (glyphs[i] === null) { 1.256 + out += ' '; 1.257 + } else { 1.258 + out += glyphs[i].fontChar; 1.259 + } 1.260 + } 1.261 + return out; 1.262 + } 1.263 + 1.264 + var opMap = null; 1.265 + 1.266 + var glyphCommands = { 1.267 + 'showText': 0, 1.268 + 'showSpacedText': 0, 1.269 + 'nextLineShowText': 0, 1.270 + 'nextLineSetSpacingShowText': 2 1.271 + }; 1.272 + 1.273 + function simplifyArgs(args) { 1.274 + if (typeof args === 'string') { 1.275 + var MAX_STRING_LENGTH = 75; 1.276 + return args.length <= MAX_STRING_LENGTH ? args : 1.277 + args.substr(0, MAX_STRING_LENGTH) + '...'; 1.278 + } 1.279 + if (typeof args !== 'object' || args === null) { 1.280 + return args; 1.281 + } 1.282 + if ('length' in args) { // array 1.283 + var simpleArgs = [], i, ii; 1.284 + var MAX_ITEMS = 10; 1.285 + for (i = 0, ii = Math.min(MAX_ITEMS, args.length); i < ii; i++) { 1.286 + simpleArgs.push(simplifyArgs(args[i])); 1.287 + } 1.288 + if (i < args.length) { 1.289 + simpleArgs.push('...'); 1.290 + } 1.291 + return simpleArgs; 1.292 + } 1.293 + var simpleObj = {}; 1.294 + for (var key in args) { 1.295 + simpleObj[key] = simplifyArgs(args[key]); 1.296 + } 1.297 + return simpleObj; 1.298 + } 1.299 + 1.300 + function Stepper(panel, pageIndex, initialBreakPoints) { 1.301 + this.panel = panel; 1.302 + this.breakPoint = 0; 1.303 + this.nextBreakPoint = null; 1.304 + this.pageIndex = pageIndex; 1.305 + this.breakPoints = initialBreakPoints; 1.306 + this.currentIdx = -1; 1.307 + this.operatorListIdx = 0; 1.308 + } 1.309 + Stepper.prototype = { 1.310 + init: function init() { 1.311 + var panel = this.panel; 1.312 + var content = c('div', 'c=continue, s=step'); 1.313 + var table = c('table'); 1.314 + content.appendChild(table); 1.315 + table.cellSpacing = 0; 1.316 + var headerRow = c('tr'); 1.317 + table.appendChild(headerRow); 1.318 + headerRow.appendChild(c('th', 'Break')); 1.319 + headerRow.appendChild(c('th', 'Idx')); 1.320 + headerRow.appendChild(c('th', 'fn')); 1.321 + headerRow.appendChild(c('th', 'args')); 1.322 + panel.appendChild(content); 1.323 + this.table = table; 1.324 + if (!opMap) { 1.325 + opMap = Object.create(null); 1.326 + for (var key in PDFJS.OPS) { 1.327 + opMap[PDFJS.OPS[key]] = key; 1.328 + } 1.329 + } 1.330 + }, 1.331 + updateOperatorList: function updateOperatorList(operatorList) { 1.332 + var self = this; 1.333 + 1.334 + function cboxOnClick() { 1.335 + var x = +this.dataset.idx; 1.336 + if (this.checked) { 1.337 + self.breakPoints.push(x); 1.338 + } else { 1.339 + self.breakPoints.splice(self.breakPoints.indexOf(x), 1); 1.340 + } 1.341 + StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints); 1.342 + } 1.343 + 1.344 + var MAX_OPERATORS_COUNT = 15000; 1.345 + if (this.operatorListIdx > MAX_OPERATORS_COUNT) { 1.346 + return; 1.347 + } 1.348 + 1.349 + var chunk = document.createDocumentFragment(); 1.350 + var operatorsToDisplay = Math.min(MAX_OPERATORS_COUNT, 1.351 + operatorList.fnArray.length); 1.352 + for (var i = this.operatorListIdx; i < operatorsToDisplay; i++) { 1.353 + var line = c('tr'); 1.354 + line.className = 'line'; 1.355 + line.dataset.idx = i; 1.356 + chunk.appendChild(line); 1.357 + var checked = this.breakPoints.indexOf(i) != -1; 1.358 + var args = operatorList.argsArray[i] || []; 1.359 + 1.360 + var breakCell = c('td'); 1.361 + var cbox = c('input'); 1.362 + cbox.type = 'checkbox'; 1.363 + cbox.className = 'points'; 1.364 + cbox.checked = checked; 1.365 + cbox.dataset.idx = i; 1.366 + cbox.onclick = cboxOnClick; 1.367 + 1.368 + breakCell.appendChild(cbox); 1.369 + line.appendChild(breakCell); 1.370 + line.appendChild(c('td', i.toString())); 1.371 + var fn = opMap[operatorList.fnArray[i]]; 1.372 + var decArgs = args; 1.373 + if (fn in glyphCommands) { 1.374 + var glyphIndex = glyphCommands[fn]; 1.375 + var glyphs = args[glyphIndex]; 1.376 + decArgs = args.slice(); 1.377 + var newArg; 1.378 + if (fn === 'showSpacedText') { 1.379 + newArg = []; 1.380 + for (var j = 0; j < glyphs.length; j++) { 1.381 + if (typeof glyphs[j] === 'number') { 1.382 + newArg.push(glyphs[j]); 1.383 + } else { 1.384 + newArg.push(glyphsToString(glyphs[j])); 1.385 + } 1.386 + } 1.387 + } else { 1.388 + newArg = glyphsToString(glyphs); 1.389 + } 1.390 + decArgs[glyphIndex] = newArg; 1.391 + } 1.392 + line.appendChild(c('td', fn)); 1.393 + line.appendChild(c('td', JSON.stringify(simplifyArgs(decArgs)))); 1.394 + } 1.395 + if (operatorsToDisplay < operatorList.fnArray.length) { 1.396 + line = c('tr'); 1.397 + var lastCell = c('td', '...'); 1.398 + lastCell.colspan = 4; 1.399 + chunk.appendChild(lastCell); 1.400 + } 1.401 + this.operatorListIdx = operatorList.fnArray.length; 1.402 + this.table.appendChild(chunk); 1.403 + }, 1.404 + getNextBreakPoint: function getNextBreakPoint() { 1.405 + this.breakPoints.sort(function(a, b) { return a - b; }); 1.406 + for (var i = 0; i < this.breakPoints.length; i++) { 1.407 + if (this.breakPoints[i] > this.currentIdx) { 1.408 + return this.breakPoints[i]; 1.409 + } 1.410 + } 1.411 + return null; 1.412 + }, 1.413 + breakIt: function breakIt(idx, callback) { 1.414 + StepperManager.selectStepper(this.pageIndex, true); 1.415 + var self = this; 1.416 + var dom = document; 1.417 + self.currentIdx = idx; 1.418 + var listener = function(e) { 1.419 + switch (e.keyCode) { 1.420 + case 83: // step 1.421 + dom.removeEventListener('keydown', listener, false); 1.422 + self.nextBreakPoint = self.currentIdx + 1; 1.423 + self.goTo(-1); 1.424 + callback(); 1.425 + break; 1.426 + case 67: // continue 1.427 + dom.removeEventListener('keydown', listener, false); 1.428 + var breakPoint = self.getNextBreakPoint(); 1.429 + self.nextBreakPoint = breakPoint; 1.430 + self.goTo(-1); 1.431 + callback(); 1.432 + break; 1.433 + } 1.434 + }; 1.435 + dom.addEventListener('keydown', listener, false); 1.436 + self.goTo(idx); 1.437 + }, 1.438 + goTo: function goTo(idx) { 1.439 + var allRows = this.panel.getElementsByClassName('line'); 1.440 + for (var x = 0, xx = allRows.length; x < xx; ++x) { 1.441 + var row = allRows[x]; 1.442 + if (row.dataset.idx == idx) { 1.443 + row.style.backgroundColor = 'rgb(251,250,207)'; 1.444 + row.scrollIntoView(); 1.445 + } else { 1.446 + row.style.backgroundColor = null; 1.447 + } 1.448 + } 1.449 + } 1.450 + }; 1.451 + return Stepper; 1.452 +})(); 1.453 + 1.454 +var Stats = (function Stats() { 1.455 + var stats = []; 1.456 + function clear(node) { 1.457 + while (node.hasChildNodes()) { 1.458 + node.removeChild(node.lastChild); 1.459 + } 1.460 + } 1.461 + function getStatIndex(pageNumber) { 1.462 + for (var i = 0, ii = stats.length; i < ii; ++i) { 1.463 + if (stats[i].pageNumber === pageNumber) { 1.464 + return i; 1.465 + } 1.466 + } 1.467 + return false; 1.468 + } 1.469 + return { 1.470 + // Properties/functions needed by PDFBug. 1.471 + id: 'Stats', 1.472 + name: 'Stats', 1.473 + panel: null, 1.474 + manager: null, 1.475 + init: function init() { 1.476 + this.panel.setAttribute('style', 'padding: 5px;'); 1.477 + PDFJS.enableStats = true; 1.478 + }, 1.479 + enabled: false, 1.480 + active: false, 1.481 + // Stats specific functions. 1.482 + add: function(pageNumber, stat) { 1.483 + if (!stat) { 1.484 + return; 1.485 + } 1.486 + var statsIndex = getStatIndex(pageNumber); 1.487 + if (statsIndex !== false) { 1.488 + var b = stats[statsIndex]; 1.489 + this.panel.removeChild(b.div); 1.490 + stats.splice(statsIndex, 1); 1.491 + } 1.492 + var wrapper = document.createElement('div'); 1.493 + wrapper.className = 'stats'; 1.494 + var title = document.createElement('div'); 1.495 + title.className = 'title'; 1.496 + title.textContent = 'Page: ' + pageNumber; 1.497 + var statsDiv = document.createElement('div'); 1.498 + statsDiv.textContent = stat.toString(); 1.499 + wrapper.appendChild(title); 1.500 + wrapper.appendChild(statsDiv); 1.501 + stats.push({ pageNumber: pageNumber, div: wrapper }); 1.502 + stats.sort(function(a, b) { return a.pageNumber - b.pageNumber; }); 1.503 + clear(this.panel); 1.504 + for (var i = 0, ii = stats.length; i < ii; ++i) { 1.505 + this.panel.appendChild(stats[i].div); 1.506 + } 1.507 + }, 1.508 + cleanup: function () { 1.509 + stats = []; 1.510 + clear(this.panel); 1.511 + } 1.512 + }; 1.513 +})(); 1.514 + 1.515 +// Manages all the debugging tools. 1.516 +var PDFBug = (function PDFBugClosure() { 1.517 + var panelWidth = 300; 1.518 + var buttons = []; 1.519 + var activePanel = null; 1.520 + 1.521 + return { 1.522 + tools: [ 1.523 + FontInspector, 1.524 + StepperManager, 1.525 + Stats 1.526 + ], 1.527 + enable: function(ids) { 1.528 + var all = false, tools = this.tools; 1.529 + if (ids.length === 1 && ids[0] === 'all') { 1.530 + all = true; 1.531 + } 1.532 + for (var i = 0; i < tools.length; ++i) { 1.533 + var tool = tools[i]; 1.534 + if (all || ids.indexOf(tool.id) !== -1) { 1.535 + tool.enabled = true; 1.536 + } 1.537 + } 1.538 + if (!all) { 1.539 + // Sort the tools by the order they are enabled. 1.540 + tools.sort(function(a, b) { 1.541 + var indexA = ids.indexOf(a.id); 1.542 + indexA = indexA < 0 ? tools.length : indexA; 1.543 + var indexB = ids.indexOf(b.id); 1.544 + indexB = indexB < 0 ? tools.length : indexB; 1.545 + return indexA - indexB; 1.546 + }); 1.547 + } 1.548 + }, 1.549 + init: function init() { 1.550 + /* 1.551 + * Basic Layout: 1.552 + * PDFBug 1.553 + * Controls 1.554 + * Panels 1.555 + * Panel 1.556 + * Panel 1.557 + * ... 1.558 + */ 1.559 + var ui = document.createElement('div'); 1.560 + ui.id = 'PDFBug'; 1.561 + 1.562 + var controls = document.createElement('div'); 1.563 + controls.setAttribute('class', 'controls'); 1.564 + ui.appendChild(controls); 1.565 + 1.566 + var panels = document.createElement('div'); 1.567 + panels.setAttribute('class', 'panels'); 1.568 + ui.appendChild(panels); 1.569 + 1.570 + var container = document.getElementById('viewerContainer'); 1.571 + container.appendChild(ui); 1.572 + container.style.right = panelWidth + 'px'; 1.573 + 1.574 + // Initialize all the debugging tools. 1.575 + var tools = this.tools; 1.576 + var self = this; 1.577 + for (var i = 0; i < tools.length; ++i) { 1.578 + var tool = tools[i]; 1.579 + var panel = document.createElement('div'); 1.580 + var panelButton = document.createElement('button'); 1.581 + panelButton.textContent = tool.name; 1.582 + panelButton.addEventListener('click', (function(selected) { 1.583 + return function(event) { 1.584 + event.preventDefault(); 1.585 + self.selectPanel(selected); 1.586 + }; 1.587 + })(i)); 1.588 + controls.appendChild(panelButton); 1.589 + panels.appendChild(panel); 1.590 + tool.panel = panel; 1.591 + tool.manager = this; 1.592 + if (tool.enabled) { 1.593 + tool.init(); 1.594 + } else { 1.595 + panel.textContent = tool.name + ' is disabled. To enable add ' + 1.596 + ' "' + tool.id + '" to the pdfBug parameter ' + 1.597 + 'and refresh (seperate multiple by commas).'; 1.598 + } 1.599 + buttons.push(panelButton); 1.600 + } 1.601 + this.selectPanel(0); 1.602 + }, 1.603 + cleanup: function cleanup() { 1.604 + for (var i = 0, ii = this.tools.length; i < ii; i++) { 1.605 + if (this.tools[i].enabled) { 1.606 + this.tools[i].cleanup(); 1.607 + } 1.608 + } 1.609 + }, 1.610 + selectPanel: function selectPanel(index) { 1.611 + if (typeof index !== 'number') { 1.612 + index = this.tools.indexOf(index); 1.613 + } 1.614 + if (index === activePanel) { 1.615 + return; 1.616 + } 1.617 + activePanel = index; 1.618 + var tools = this.tools; 1.619 + for (var j = 0; j < tools.length; ++j) { 1.620 + if (j == index) { 1.621 + buttons[j].setAttribute('class', 'active'); 1.622 + tools[j].active = true; 1.623 + tools[j].panel.removeAttribute('hidden'); 1.624 + } else { 1.625 + buttons[j].setAttribute('class', ''); 1.626 + tools[j].active = false; 1.627 + tools[j].panel.setAttribute('hidden', 'true'); 1.628 + } 1.629 + } 1.630 + } 1.631 + }; 1.632 +})();