1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5cr.define('accessibility', function() { 6 'use strict'; 7 8 // Keep in sync with view_message_enums.h 9 var AccessibilityModeFlag = { 10 Platform: 1 << 0, 11 FullTree: 1 << 1 12 } 13 14 var AccessibilityMode = { 15 Off: 0, 16 Complete: 17 AccessibilityModeFlag.Platform | AccessibilityModeFlag.FullTree, 18 EditableTextOnly: AccessibilityModeFlag.Platform, 19 TreeOnly: AccessibilityModeFlag.FullTree 20 } 21 22 function isAccessibilityComplete(mode) { 23 return ((mode & AccessibilityMode.Complete) == AccessibilityMode.Complete); 24 } 25 26 function requestData() { 27 var xhr = new XMLHttpRequest(); 28 xhr.open('GET', 'targets-data.json', false); 29 xhr.send(null); 30 if (xhr.status === 200) { 31 console.log(xhr.responseText); 32 return JSON.parse(xhr.responseText); 33 } 34 return []; 35 } 36 37 // TODO(aboxhall): add a mechanism to request individual and global a11y 38 // mode, xhr them on toggle... or just re-requestData and be smarter about 39 // ID-ing rows? 40 41 function toggleAccessibility(data, element) { 42 chrome.send('toggleAccessibility', 43 [String(data.processId), String(data.routeId)]); 44 var a11y_was_on = (element.textContent.match(/on/) != null); 45 element.textContent = ' accessibility ' + (a11y_was_on ? ' off' : ' on'); 46 var row = element.parentElement; 47 if (a11y_was_on) { 48 while (row.lastChild != element) 49 row.removeChild(row.lastChild); 50 } else { 51 row.appendChild(document.createTextNode(' | ')); 52 row.appendChild(createShowAccessibilityTreeElement(data, row, false)); 53 } 54 } 55 56 function requestAccessibilityTree(data, element) { 57 chrome.send('requestAccessibilityTree', 58 [String(data.processId), String(data.routeId)]); 59 } 60 61 function toggleGlobalAccessibility() { 62 chrome.send('toggleGlobalAccessibility'); 63 document.location.reload(); // FIXME see TODO above 64 } 65 66 function initialize() { 67 console.log('initialize'); 68 var data = requestData(); 69 70 addGlobalAccessibilityModeToggle(data['global_a11y_mode']); 71 72 $('pages').textContent = ''; 73 74 var list = data['list']; 75 for (var i = 0; i < list.length; i++) { 76 addToPagesList(list[i]); 77 } 78 } 79 80 function addGlobalAccessibilityModeToggle(global_a11y_mode) { 81 var full_a11y_on = isAccessibilityComplete(global_a11y_mode); 82 $('toggle_global').textContent = (full_a11y_on ? 'on' : 'off'); 83 $('toggle_global').addEventListener('click', 84 toggleGlobalAccessibility); 85 } 86 87 function addToPagesList(data) { 88 // TODO: iterate through data and pages rows instead 89 var id = data['processId'] + '.' + data['routeId']; 90 var row = document.createElement('div'); 91 row.className = 'row'; 92 row.id = id; 93 formatRow(row, data); 94 95 row.processId = data.processId; 96 row.routeId = data.routeId; 97 98 var list = $('pages'); 99 list.appendChild(row); 100 } 101 102 function formatRow(row, data) { 103 if (!('url' in data)) { 104 if ('error' in data) { 105 row.appendChild(createErrorMessageElement(data, row)); 106 return; 107 } 108 } 109 var properties = ['favicon_url', 'name', 'url']; 110 for (var j = 0; j < properties.length; j++) 111 row.appendChild(formatValue(data, properties[j])); 112 113 row.appendChild(createToggleAccessibilityElement(data)); 114 if (isAccessibilityComplete(data['a11y_mode'])) { 115 row.appendChild(document.createTextNode(' | ')); 116 if ('tree' in data) { 117 row.appendChild(createShowAccessibilityTreeElement(data, row, true)); 118 row.appendChild(document.createTextNode(' | ')); 119 row.appendChild(createHideAccessibilityTreeElement(row.id)); 120 row.appendChild(createAccessibilityTreeElement(data)); 121 } 122 else { 123 row.appendChild(createShowAccessibilityTreeElement(data, row, false)); 124 if ('error' in data) 125 row.appendChild(createErrorMessageElement(data, row)); 126 } 127 } 128 } 129 130 function formatValue(data, property) { 131 var value = data[property]; 132 133 if (property == 'favicon_url') { 134 var faviconElement = document.createElement('img'); 135 if (value) 136 faviconElement.src = value; 137 faviconElement.alt = ""; 138 return faviconElement; 139 } 140 141 var text = value ? String(value) : ''; 142 if (text.length > 100) 143 text = text.substring(0, 100) + '\u2026'; // ellipsis 144 145 var span = document.createElement('span'); 146 span.textContent = ' ' + text + ' '; 147 span.className = property; 148 return span; 149 } 150 151 function createToggleAccessibilityElement(data) { 152 var link = document.createElement('a'); 153 link.setAttribute('href', '#'); 154 var full_a11y_on = isAccessibilityComplete(data['a11y_mode']); 155 link.textContent = 'accessibility ' + (full_a11y_on ? 'on' : 'off'); 156 link.addEventListener('click', 157 toggleAccessibility.bind(this, data, link)); 158 return link; 159 } 160 161 function createShowAccessibilityTreeElement(data, row, opt_refresh) { 162 var link = document.createElement('a'); 163 link.setAttribute('href', '#'); 164 if (opt_refresh) 165 link.textContent = 'refresh accessibility tree'; 166 else 167 link.textContent = 'show accessibility tree'; 168 link.id = row.id + ':showTree'; 169 link.addEventListener('click', 170 requestAccessibilityTree.bind(this, data, link)); 171 return link; 172 } 173 174 function createHideAccessibilityTreeElement(id) { 175 var link = document.createElement('a'); 176 link.setAttribute('href', '#'); 177 link.textContent = 'hide accessibility tree'; 178 link.addEventListener('click', 179 function() { 180 $(id + ':showTree').textContent = 'show accessibility tree'; 181 var existingTreeElements = $(id).getElementsByTagName('pre'); 182 for (var i = 0; i < existingTreeElements.length; i++) 183 $(id).removeChild(existingTreeElements[i]); 184 var row = $(id); 185 while (row.lastChild != $(id + ':showTree')) 186 row.removeChild(row.lastChild); 187 }); 188 return link; 189 } 190 191 function createErrorMessageElement(data) { 192 var errorMessageElement = document.createElement('div'); 193 var errorMessage = data.error; 194 errorMessageElement.innerHTML = errorMessage + ' '; 195 var closeLink = document.createElement('a'); 196 closeLink.href='#'; 197 closeLink.textContent = '[close]'; 198 closeLink.addEventListener('click', function() { 199 var parentElement = errorMessageElement.parentElement; 200 parentElement.removeChild(errorMessageElement); 201 if (parentElement.childElementCount == 0) 202 parentElement.parentElement.removeChild(parentElement); 203 }); 204 errorMessageElement.appendChild(closeLink); 205 return errorMessageElement; 206 } 207 208 function showTree(data) { 209 var id = data.processId + '.' + data.routeId; 210 var row = $(id); 211 if (!row) 212 return; 213 214 row.textContent = ''; 215 formatRow(row, data); 216 } 217 218 function createAccessibilityTreeElement(data) { 219 var treeElement = document.createElement('pre'); 220 var tree = data.tree; 221 treeElement.textContent = tree; 222 return treeElement; 223 } 224 225 return { 226 initialize: initialize, 227 showTree: showTree 228 }; 229}); 230 231document.addEventListener('DOMContentLoaded', accessibility.initialize); 232