1// Copyright (c) 2010 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 5function $(id) { 6 return document.getElementById(id); 7} 8 9// Returns the largest size icon, or a default icon, for the given |app|. 10function getIconURL(app) { 11 if (!app.icons || app.icons.length == 0) { 12 return chrome.extension.getURL("icon.png"); 13 } 14 var largest = {size:0}; 15 for (var i = 0; i < app.icons.length; i++) { 16 var icon = app.icons[i]; 17 if (icon.size > largest.size) { 18 largest = icon; 19 } 20 } 21 return largest.url; 22} 23 24function launchApp(id) { 25 chrome.management.launchApp(id); 26 window.close(); // Only needed on OSX because of crbug.com/63594 27} 28 29// Adds DOM nodes for |app| into |appsDiv|. 30function addApp(appsDiv, app, selected) { 31 var div = document.createElement("div"); 32 div.className = "app" + (selected ? " app_selected" : ""); 33 34 div.onclick = function() { 35 launchApp(app.id); 36 }; 37 38 var img = document.createElement("img"); 39 img.src = getIconURL(app); 40 div.appendChild(img); 41 42 var title = document.createElement("span"); 43 title.className = "app_title"; 44 title.innerText = app.name; 45 div.appendChild(title); 46 47 appsDiv.appendChild(div); 48} 49 50// The list of all apps & extensions. 51var completeList = []; 52 53// A filtered list of apps we actually want to show. 54var appList = []; 55 56// The index of an app in |appList| that should be highlighted. 57var selectedIndex = 0; 58 59function reloadAppDisplay() { 60 var appsDiv = $("apps"); 61 62 // Empty the current content. 63 appsDiv.innerHTML = ""; 64 65 for (var i = 0; i < appList.length; i++) { 66 var item = appList[i]; 67 addApp(appsDiv, item, i == selectedIndex); 68 } 69} 70 71// Puts only enabled apps from completeList into appList. 72function rebuildAppList(filter) { 73 selectedIndex = 0; 74 appList = []; 75 for (var i = 0; i < completeList.length; i++){ 76 var item = completeList[i]; 77 // Skip extensions and disabled apps. 78 if (!item.isApp || !item.enabled) { 79 continue; 80 } 81 if (filter && item.name.toLowerCase().search(filter) < 0) { 82 continue; 83 } 84 appList.push(item); 85 } 86} 87 88// In order to keep the popup bubble from shrinking as your search narrows the 89// list of apps shown, we set an explicit width on the outermost div. 90var didSetExplicitWidth = false; 91 92function adjustWidthIfNeeded(filter) { 93 if (filter.length > 0 && !didSetExplicitWidth) { 94 // Set an explicit width, correcting for any scroll bar present. 95 var outer = $("outer"); 96 var correction = window.innerWidth - document.documentElement.clientWidth; 97 var width = outer.offsetWidth; 98 $("spacer_dummy").style.width = width + correction + "px"; 99 didSetExplicitWidth = true; 100 } 101} 102 103// Shows the list of apps based on the search box contents. 104function onSearchInput() { 105 var filter = $("search").value; 106 adjustWidthIfNeeded(filter); 107 rebuildAppList(filter); 108 reloadAppDisplay(); 109} 110 111function compare(a, b) { 112 return (a > b) ? 1 : (a == b ? 0 : -1); 113} 114 115function compareByName(app1, app2) { 116 return compare(app1.name.toLowerCase(), app2.name.toLowerCase()); 117} 118 119function onLoad() { 120 chrome.management.getAll(function(info) { 121 var appCount = 0; 122 for (var i = 0; i < info.length; i++) { 123 if (info[i].isApp) { 124 appCount++; 125 } 126 } 127 if (appCount == 0) { 128 $("search").style.display = "none"; 129 $("appstore_link").style.display = ""; 130 return; 131 } 132 completeList = info.sort(compareByName); 133 onSearchInput(); 134 }); 135} 136 137// Changes the selected app in the list. 138function changeSelection(newIndex) { 139 if (newIndex >= 0 && newIndex <= appList.length - 1) { 140 selectedIndex = newIndex; 141 reloadAppDisplay(); 142 143 var selected = document.getElementsByClassName("app_selected")[0]; 144 var rect = selected.getBoundingClientRect(); 145 if (newIndex == 0) { 146 window.scrollTo(0, 0); 147 } else if (newIndex == appList.length - 1) { 148 window.scrollTo(0, document.height); 149 } else if (rect.top < 0) { 150 window.scrollBy(0, rect.top); 151 } else if (rect.bottom > innerHeight) { 152 window.scrollBy(0, rect.bottom - innerHeight); 153 } 154 } 155} 156 157var keys = { 158 ENTER : 13, 159 ESCAPE : 27, 160 END : 35, 161 HOME : 36, 162 LEFT : 37, 163 UP : 38, 164 RIGHT : 39, 165 DOWN : 40 166}; 167 168// Set up a key event handler that handles moving the selected app up/down, 169// hitting enter to launch the selected app, as well as auto-focusing the 170// search box as soon as you start typing. 171window.onkeydown = function(event) { 172 switch (event.keyCode) { 173 case keys.DOWN: 174 changeSelection(selectedIndex + 1); 175 break; 176 case keys.UP: 177 changeSelection(selectedIndex - 1); 178 break; 179 case keys.HOME: 180 changeSelection(0); 181 break; 182 case keys.END: 183 changeSelection(appList.length - 1); 184 break; 185 case keys.ENTER: 186 var app = appList[selectedIndex]; 187 if (app) { 188 launchApp(app.id); 189 } 190 break; 191 default: 192 // Focus the search box and return true so you can just start typing even 193 // when the search box isn't focused. 194 $("search").focus(); 195 return true; 196 } 197 return false; 198}; 199