UNPKG

15.5 kBJavaScriptView Raw
1/*
2 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 */
23
24
25/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
26/*global require, define, brackets: true, $, PathUtils, window, navigator, Mustache */
27
28require.config({
29 paths: {
30 "text" : "thirdparty/text",
31 "i18n" : "thirdparty/i18n"
32 },
33 // Use custom brackets property until CEF sets the correct navigator.language
34 // NOTE: When we change to navigator.language here, we also should change to
35 // navigator.language in ExtensionLoader (when making require contexts for each
36 // extension).
37 locale: window.localStorage.getItem("locale") || (typeof (brackets) !== "undefined" ? brackets.app.language : navigator.language)
38});
39
40/**
41 * brackets is the root of the Brackets codebase. This file pulls in all other modules as
42 * dependencies (or dependencies thereof), initializes the UI, and binds global menus & keyboard
43 * shortcuts to their Commands.
44 *
45 * TODO: (issue #264) break out the definition of brackets into a separate module from the application controller logic
46 *
47 * Unlike other modules, this one can be accessed without an explicit require() because it exposes
48 * a global object, window.brackets.
49 */
50define(function (require, exports, module) {
51 "use strict";
52
53 // Load dependent non-module scripts
54 require("widgets/bootstrap-dropdown");
55 require("widgets/bootstrap-modal");
56 require("thirdparty/path-utils/path-utils.min");
57 require("thirdparty/smart-auto-complete/jquery.smart_autocomplete");
58
59 // Load LiveDeveopment
60 require("LiveDevelopment/main");
61
62 // Load dependent modules
63 var Global = require("utils/Global"),
64 AppInit = require("utils/AppInit"),
65 ProjectManager = require("project/ProjectManager"),
66 DocumentManager = require("document/DocumentManager"),
67 EditorManager = require("editor/EditorManager"),
68 CSSInlineEditor = require("editor/CSSInlineEditor"),
69 JSUtils = require("language/JSUtils"),
70 WorkingSetView = require("project/WorkingSetView"),
71 WorkingSetSort = require("project/WorkingSetSort"),
72 DocumentCommandHandlers = require("document/DocumentCommandHandlers"),
73 FileViewController = require("project/FileViewController"),
74 FileSyncManager = require("project/FileSyncManager"),
75 KeyBindingManager = require("command/KeyBindingManager"),
76 Commands = require("command/Commands"),
77 CommandManager = require("command/CommandManager"),
78 CodeHintManager = require("editor/CodeHintManager"),
79 JSLintUtils = require("language/JSLintUtils"),
80 PerfUtils = require("utils/PerfUtils"),
81 FileIndexManager = require("project/FileIndexManager"),
82 QuickOpen = require("search/QuickOpen"),
83 Menus = require("command/Menus"),
84 FileUtils = require("file/FileUtils"),
85 MainViewHTML = require("text!htmlContent/main-view.html"),
86 Strings = require("strings"),
87 Dialogs = require("widgets/Dialogs"),
88 ExtensionLoader = require("utils/ExtensionLoader"),
89 SidebarView = require("project/SidebarView"),
90 Async = require("utils/Async"),
91 UpdateNotification = require("utils/UpdateNotification"),
92 UrlParams = require("utils/UrlParams").UrlParams,
93 NativeFileSystem = require("file/NativeFileSystem").NativeFileSystem,
94 PreferencesManager = require("preferences/PreferencesManager"),
95 Resizer = require("utils/Resizer");
96
97 // Local variables
98 var params = new UrlParams(),
99 PREFERENCES_CLIENT_ID = "com.adobe.brackets.startup";
100
101 // read URL params
102 params.parse();
103
104 //Load modules that self-register and just need to get included in the main project
105 require("document/ChangedDocumentTracker");
106 require("editor/EditorCommandHandlers");
107 require("view/ViewCommandHandlers");
108 require("debug/DebugCommandHandlers");
109 require("help/HelpCommandHandlers");
110 require("search/FindInFiles");
111 require("search/FindReplace");
112 require("utils/ExtensionUtils");
113
114 function _initExtensions() {
115 // allow unit tests to override which plugin folder(s) to load
116 var paths = params.get("extensions");
117
118 if (!paths) {
119 paths = "default,dev," + ExtensionLoader.getUserExtensionPath();
120 }
121
122 return Async.doInParallel(paths.split(","), function (item) {
123 var extensionPath = item;
124
125 // If the item has "/" in it, assume it is a full path. Otherwise, load
126 // from our source path + "/extensions/".
127 if (item.indexOf("/") === -1) {
128 extensionPath = FileUtils.getNativeBracketsDirectoryPath() + "/extensions/" + item;
129 }
130
131 return ExtensionLoader.loadAllExtensionsInNativeDirectory(extensionPath);
132 });
133 }
134
135 function _initTest() {
136 // TODO: (issue #265) Make sure the "test" object is not included in final builds
137 // All modules that need to be tested from the context of the application
138 // must to be added to this object. The unit tests cannot just pull
139 // in the modules since they would run in context of the unit test window,
140 // and would not have access to the app html/css.
141 brackets.test = {
142 PreferencesManager : require("preferences/PreferencesManager"),
143 ProjectManager : ProjectManager,
144 DocumentCommandHandlers : DocumentCommandHandlers,
145 FileViewController : FileViewController,
146 DocumentManager : DocumentManager,
147 EditorManager : EditorManager,
148 Commands : Commands,
149 WorkingSetView : WorkingSetView,
150 JSLintUtils : JSLintUtils,
151 PerfUtils : PerfUtils,
152 JSUtils : JSUtils,
153 CommandManager : require("command/CommandManager"),
154 FileSyncManager : FileSyncManager,
155 FileIndexManager : FileIndexManager,
156 Menus : Menus,
157 KeyBindingManager : KeyBindingManager,
158 CodeHintManager : CodeHintManager,
159 CSSUtils : require("language/CSSUtils"),
160 LiveDevelopment : require("LiveDevelopment/LiveDevelopment"),
161 DOMAgent : require("LiveDevelopment/Agents/DOMAgent"),
162 Inspector : require("LiveDevelopment/Inspector/Inspector"),
163 NativeApp : require("utils/NativeApp"),
164 ExtensionUtils : require("utils/ExtensionUtils"),
165 UpdateNotification : require("utils/UpdateNotification"),
166 doneLoading : false
167 };
168
169 AppInit.appReady(function () {
170 brackets.test.doneLoading = true;
171 });
172 }
173
174 function _initDragAndDropListeners() {
175 // Prevent unhandled drag and drop of files into the browser from replacing
176 // the entire Brackets app. This doesn't prevent children from choosing to
177 // handle drops.
178 $(window.document.body)
179 .on("dragover", function (event) {
180 if (event.originalEvent.dataTransfer.files) {
181 event.stopPropagation();
182 event.preventDefault();
183 event.originalEvent.dataTransfer.dropEffect = "none";
184 }
185 })
186 .on("drop", function (event) {
187 if (event.originalEvent.dataTransfer.files) {
188 event.stopPropagation();
189 event.preventDefault();
190 }
191 });
192 }
193
194 function _initCommandHandlers() {
195 // Most command handlers are automatically registered when their module is loaded (see "modules
196 // that self-register" above for some). A few commands need an extra kick here though:
197
198 DocumentCommandHandlers.init($("#main-toolbar"));
199 }
200
201 function _initWindowListeners() {
202 // TODO: (issue 269) to support IE, need to listen to document instead (and even then it may not work when focus is in an input field?)
203 $(window).focus(function () {
204 FileSyncManager.syncOpenDocuments();
205 FileIndexManager.markDirty();
206 });
207
208 }
209
210 function _onReady() {
211 // Add the platform (mac or win) to the body tag so we can have platform-specific CSS rules
212 $("body").addClass("platform-" + brackets.platform);
213
214 EditorManager.setEditorHolder($("#editor-holder"));
215
216 _initDragAndDropListeners();
217 _initCommandHandlers();
218 KeyBindingManager.init();
219 Menus.init(); // key bindings should be initialized first
220 _initWindowListeners();
221
222 // Use quiet scrollbars if we aren't on Lion. If we're on Lion, only
223 // use native scroll bars when the mouse is not plugged in or when
224 // using the "Always" scroll bar setting.
225 var osxMatch = /Mac OS X 10\D([\d+])\D/.exec(navigator.userAgent);
226 if (osxMatch && osxMatch[1] && Number(osxMatch[1]) >= 7) {
227 // test a scrolling div for scrollbars
228 var $testDiv = $("<div style='position:fixed;left:-50px;width:50px;height:50px;overflow:auto;'><div style='width:100px;height:100px;'/></div>").appendTo(window.document.body);
229
230 if ($testDiv.outerWidth() === $testDiv.get(0).clientWidth) {
231 $(".sidebar").removeClass("quiet-scrollbars");
232 }
233
234 $testDiv.remove();
235 }
236
237 PerfUtils.addMeasurement("Application Startup");
238
239 // finish UI initialization before loading extensions
240 var initialProjectPath = ProjectManager.getInitialProjectPath();
241 ProjectManager.openProject(initialProjectPath).always(function () {
242 _initTest();
243
244 // Create a new DirectoryEntry and call getDirectory() on the user extension
245 // directory. If the directory doesn't exist, it will be created.
246 // Note that this is an async call and there are no success or failure functions passed
247 // in. If the directory *doesn't* exist, it will be created. Extension loading may happen
248 // before the directory is finished being created, but that is okay, since the extension
249 // loading will work correctly without this directory.
250 // If the directory *does* exist, nothing else needs to be done. It will be scanned normally
251 // during extension loading.
252 var extensionPath = ExtensionLoader.getUserExtensionPath();
253 new NativeFileSystem.DirectoryEntry().getDirectory(extensionPath,
254 {create: true});
255
256 // Create the extensions/disabled directory, too.
257 var disabledExtensionPath = extensionPath.replace(/\/user$/, "/disabled");
258 new NativeFileSystem.DirectoryEntry().getDirectory(disabledExtensionPath,
259 {create: true});
260
261 // Load all extensions, and when done fire APP_READY (even if some extensions failed
262 // to load or initialize)
263 _initExtensions().always(function () {
264 AppInit._dispatchReady(AppInit.APP_READY);
265 });
266
267 // If this is the first launch, and we have an index.html file in the project folder (which should be
268 // the samples folder on first launch), open it automatically. (We explicitly check for the
269 // samples folder in case this is the first time we're launching Brackets after upgrading from
270 // an old version that might not have set the "afterFirstLaunch" pref.)
271 var prefs = PreferencesManager.getPreferenceStorage(PREFERENCES_CLIENT_ID);
272 if (!params.get("skipSampleProjectLoad") && !prefs.getValue("afterFirstLaunch")) {
273 prefs.setValue("afterFirstLaunch", "true");
274 if (ProjectManager.isWelcomeProjectPath(initialProjectPath)) {
275 var dirEntry = new NativeFileSystem.DirectoryEntry(initialProjectPath);
276 dirEntry.getFile("index.html", {}, function (fileEntry) {
277 CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: fileEntry.fullPath });
278 });
279 }
280 }
281 });
282
283 // Check for updates
284 if (!params.get("skipUpdateCheck") && !brackets.inBrowser) {
285 UpdateNotification.checkForUpdate();
286 }
287 }
288
289 // Prevent unhandled middle button clicks from triggering native behavior
290 // Example: activating AutoScroll (see #510)
291 $("html").on("mousedown", ".inline-widget", function (e) {
292 if (e.button === 1) {
293 e.preventDefault();
294 }
295 });
296
297 // Localize MainViewHTML and inject into <BODY> tag
298 var templateVars = $.extend({
299 ABOUT_ICON : brackets.config.about_icon,
300 APP_NAME_ABOUT_BOX : brackets.config.app_name_about,
301 VERSION : brackets.metadata.version
302 }, Strings);
303
304 $("body").html(Mustache.render(MainViewHTML, templateVars));
305
306 // Update title
307 $("title").text(brackets.config.app_title);
308
309 // Dispatch htmlReady callbacks
310 AppInit._dispatchReady(AppInit.HTML_READY);
311
312 $(window.document).ready(_onReady);
313
314});