ui.js (5654B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 AUDIT, 9 ENABLE, 10 RESET, 11 SELECT, 12 HIGHLIGHT, 13 UNHIGHLIGHT, 14 UPDATE_CAN_BE_DISABLED, 15 UPDATE_CAN_BE_ENABLED, 16 UPDATE_PREF, 17 UPDATE_DETAILS, 18 PREF_KEYS, 19 PREFS, 20 UPDATE_DISPLAY_TABBING_ORDER, 21 } = require("resource://devtools/client/accessibility/constants.js"); 22 23 const TreeView = ChromeUtils.importESModule( 24 "resource://devtools/client/shared/components/tree/TreeView.mjs" 25 ).default; 26 27 /** 28 * Initial state definition 29 */ 30 function getInitialState() { 31 return { 32 enabled: false, 33 canBeDisabled: true, 34 canBeEnabled: true, 35 selected: null, 36 highlighted: null, 37 expanded: new Set(), 38 [PREFS.SCROLL_INTO_VIEW]: Services.prefs.getBoolPref( 39 PREF_KEYS[PREFS.SCROLL_INTO_VIEW], 40 false 41 ), 42 tabbingOrderDisplayed: false, 43 supports: {}, 44 }; 45 } 46 47 /** 48 * Maintain ui components of the accessibility panel. 49 */ 50 function ui(state = getInitialState(), action) { 51 switch (action.type) { 52 case ENABLE: 53 return onToggle(state, action, true); 54 case UPDATE_CAN_BE_DISABLED: 55 return onCanBeDisabledChange(state, action); 56 case UPDATE_CAN_BE_ENABLED: 57 return onCanBeEnabledChange(state, action); 58 case UPDATE_PREF: 59 return onPrefChange(state, action); 60 case UPDATE_DETAILS: 61 return onUpdateDetails(state, action); 62 case HIGHLIGHT: 63 return onHighlight(state, action); 64 case AUDIT: 65 return onAudit(state, action); 66 case UNHIGHLIGHT: 67 return onUnhighlight(state, action); 68 case SELECT: 69 return onSelect(state, action); 70 case RESET: 71 return onReset(state, action); 72 case UPDATE_DISPLAY_TABBING_ORDER: 73 return onUpdateDisplayTabbingOrder(state, action); 74 default: 75 return state; 76 } 77 } 78 79 function onUpdateDetails(state) { 80 if (!state.selected) { 81 return state; 82 } 83 84 // Clear selected state that should only be set when select action is 85 // performed. 86 return Object.assign({}, state, { selected: null }); 87 } 88 89 function onUnhighlight(state) { 90 return Object.assign({}, state, { highlighted: null }); 91 } 92 93 function updateExpandedNodes(expanded, ancestry) { 94 expanded = new Set(expanded); 95 const path = ancestry.reduceRight((accPath, { accessible }) => { 96 accPath = TreeView.subPath(accPath, accessible.actorID); 97 expanded.add(accPath); 98 return accPath; 99 }, ""); 100 101 return { path, expanded }; 102 } 103 104 function onAudit(state, { response: ancestries, error }) { 105 if (error) { 106 console.warn("Error running audit", error); 107 return state; 108 } 109 110 let expanded = new Set(state.expanded); 111 for (const ancestry of ancestries) { 112 ({ expanded } = updateExpandedNodes(expanded, ancestry)); 113 } 114 115 return { 116 ...state, 117 expanded, 118 }; 119 } 120 121 function onHighlight(state, { accessible, response: ancestry, error }) { 122 if (error) { 123 console.warn("Error fetching ancestry", error); 124 return state; 125 } 126 127 const { expanded } = updateExpandedNodes(state.expanded, ancestry); 128 return Object.assign({}, state, { expanded, highlighted: accessible }); 129 } 130 131 function onSelect(state, { accessible, response: ancestry, error }) { 132 if (error) { 133 console.warn("Error fetching ancestry", error); 134 return state; 135 } 136 137 const { path, expanded } = updateExpandedNodes(state.expanded, ancestry); 138 const selected = TreeView.subPath(path, accessible.actorID); 139 140 return Object.assign({}, state, { expanded, selected }); 141 } 142 143 /** 144 * Handle "canBeDisabled" flag update for accessibility service 145 * 146 * @param {object} state Current ui state 147 * @param {object} action Redux action object 148 * @return {object} updated state 149 */ 150 function onCanBeDisabledChange(state, { canBeDisabled }) { 151 return Object.assign({}, state, { canBeDisabled }); 152 } 153 154 /** 155 * Handle "canBeEnabled" flag update for accessibility service 156 * 157 * @param {object} state Current ui state. 158 * @param {object} action Redux action object 159 * @return {object} updated state 160 */ 161 function onCanBeEnabledChange(state, { canBeEnabled }) { 162 return Object.assign({}, state, { canBeEnabled }); 163 } 164 165 /** 166 * Handle pref update for accessibility panel. 167 * 168 * @param {object} state Current ui state. 169 * @param {object} action Redux action object 170 * @return {object} updated state 171 */ 172 function onPrefChange(state, { name, value }) { 173 return { 174 ...state, 175 [name]: value, 176 }; 177 } 178 179 /** 180 * Handle reset action for the accessibility panel UI. 181 * 182 * @param {object} state Current ui state. 183 * @param {object} action Redux action object 184 * @return {object} updated state 185 */ 186 function onReset(state, { enabled, canBeDisabled, canBeEnabled, supports }) { 187 const newState = { 188 ...getInitialState(), 189 enabled, 190 canBeDisabled, 191 canBeEnabled, 192 supports, 193 }; 194 195 return newState; 196 } 197 198 /** 199 * Handle accessibilty service enabling/disabling. 200 * 201 * @param {object} state Current accessibility services enabled state. 202 * @param {object} action Redux action object 203 * @param {boolean} enabled New enabled state. 204 * @return {object} updated state 205 */ 206 function onToggle(state, { error }, enabled) { 207 if (error) { 208 console.warn("Error enabling accessibility service: ", error); 209 return state; 210 } 211 212 return Object.assign({}, state, { enabled }); 213 } 214 215 function onUpdateDisplayTabbingOrder(state, { error, tabbingOrderDisplayed }) { 216 if (error) { 217 console.warn("Error updating displaying tabbing order: ", error); 218 return state; 219 } 220 221 return Object.assign({}, state, { tabbingOrderDisplayed }); 222 } 223 224 exports.ui = ui;