| /* |
| * Copyright (C) 2011 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| |
| /** |
| * @constructor |
| * @extends {WebInspector.Object} |
| * @implements {WebInspector.ContentProvider} |
| * @param {!WebInspector.Project} project |
| * @param {string} parentPath |
| * @param {string} name |
| * @param {string} originURL |
| * @param {string} url |
| * @param {!WebInspector.ResourceType} contentType |
| */ |
| WebInspector.UISourceCode = function(project, parentPath, name, originURL, url, contentType) |
| { |
| this._project = project; |
| this._parentPath = parentPath; |
| this._name = name; |
| this._originURL = originURL; |
| this._url = url; |
| this._contentType = contentType; |
| /** @type {!Array.<function(?string)>} */ |
| this._requestContentCallbacks = []; |
| /** @type {!Array.<!WebInspector.PresentationMessage>} */ |
| this._consoleMessages = []; |
| |
| /** @type {!Array.<!WebInspector.Revision>} */ |
| this.history = []; |
| } |
| |
| WebInspector.UISourceCode.Events = { |
| WorkingCopyChanged: "WorkingCopyChanged", |
| WorkingCopyCommitted: "WorkingCopyCommitted", |
| TitleChanged: "TitleChanged", |
| SavedStateUpdated: "SavedStateUpdated", |
| ConsoleMessageAdded: "ConsoleMessageAdded", |
| ConsoleMessageRemoved: "ConsoleMessageRemoved", |
| ConsoleMessagesCleared: "ConsoleMessagesCleared", |
| SourceMappingChanged: "SourceMappingChanged", |
| } |
| |
| WebInspector.UISourceCode.prototype = { |
| /** |
| * @return {string} |
| */ |
| get url() |
| { |
| return this._url; |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| name: function() |
| { |
| return this._name; |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| parentPath: function() |
| { |
| return this._parentPath; |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| path: function() |
| { |
| return this._parentPath ? this._parentPath + "/" + this._name : this._name; |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| fullDisplayName: function() |
| { |
| return this._project.displayName() + "/" + (this._parentPath ? this._parentPath + "/" : "") + this.displayName(true); |
| }, |
| |
| /** |
| * @param {boolean=} skipTrim |
| * @return {string} |
| */ |
| displayName: function(skipTrim) |
| { |
| var displayName = this.name() || WebInspector.UIString("(index)"); |
| return skipTrim ? displayName : displayName.trimEnd(100); |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| uri: function() |
| { |
| var path = this.path(); |
| if (!this._project.id()) |
| return path; |
| if (!path) |
| return this._project.id(); |
| return this._project.id() + "/" + path; |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| originURL: function() |
| { |
| return this._originURL; |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| canRename: function() |
| { |
| return this._project.canRename(); |
| }, |
| |
| /** |
| * @param {string} newName |
| * @param {function(boolean)} callback |
| */ |
| rename: function(newName, callback) |
| { |
| this._project.rename(this, newName, innerCallback.bind(this)); |
| |
| /** |
| * @param {boolean} success |
| * @param {string=} newName |
| * @param {string=} newURL |
| * @param {string=} newOriginURL |
| * @param {!WebInspector.ResourceType=} newContentType |
| * @this {WebInspector.UISourceCode} |
| */ |
| function innerCallback(success, newName, newURL, newOriginURL, newContentType) |
| { |
| if (success) |
| this._updateName(/** @type {string} */ (newName), /** @type {string} */ (newURL), /** @type {string} */ (newOriginURL), /** @type {!WebInspector.ResourceType} */ (newContentType)); |
| callback(success); |
| } |
| }, |
| |
| remove: function() |
| { |
| this._project.deleteFile(this.path()); |
| }, |
| |
| /** |
| * @param {string} name |
| * @param {string} url |
| * @param {string} originURL |
| * @param {!WebInspector.ResourceType=} contentType |
| */ |
| _updateName: function(name, url, originURL, contentType) |
| { |
| var oldURI = this.uri(); |
| this._name = name; |
| if (url) |
| this._url = url; |
| if (originURL) |
| this._originURL = originURL; |
| if (contentType) |
| this._contentType = contentType; |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.TitleChanged, oldURI); |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| contentURL: function() |
| { |
| return this.originURL(); |
| }, |
| |
| /** |
| * @return {!WebInspector.ResourceType} |
| */ |
| contentType: function() |
| { |
| return this._contentType; |
| }, |
| |
| /** |
| * @return {!WebInspector.Project} |
| */ |
| project: function() |
| { |
| return this._project; |
| }, |
| |
| /** |
| * @param {function(?Date, ?number)} callback |
| */ |
| requestMetadata: function(callback) |
| { |
| this._project.requestMetadata(this, callback); |
| }, |
| |
| /** |
| * @param {function(?string)} callback |
| */ |
| requestContent: function(callback) |
| { |
| if (this._content || this._contentLoaded) { |
| callback(this._content); |
| return; |
| } |
| this._requestContentCallbacks.push(callback); |
| if (this._requestContentCallbacks.length === 1) |
| this._project.requestFileContent(this, this._fireContentAvailable.bind(this)); |
| }, |
| |
| /** |
| * @param {function()} callback |
| */ |
| _pushCheckContentUpdatedCallback: function(callback) |
| { |
| if (!this._checkContentUpdatedCallbacks) |
| this._checkContentUpdatedCallbacks = []; |
| this._checkContentUpdatedCallbacks.push(callback); |
| }, |
| |
| _terminateContentCheck: function() |
| { |
| delete this._checkingContent; |
| if (this._checkContentUpdatedCallbacks) { |
| this._checkContentUpdatedCallbacks.forEach(function(callback) { callback(); }); |
| delete this._checkContentUpdatedCallbacks; |
| } |
| }, |
| |
| /** |
| * @param {function()=} callback |
| */ |
| checkContentUpdated: function(callback) |
| { |
| callback = callback || function() {}; |
| if (!this._project.canSetFileContent()) { |
| callback(); |
| return; |
| } |
| this._pushCheckContentUpdatedCallback(callback); |
| |
| if (this._checkingContent) { |
| return; |
| } |
| this._checkingContent = true; |
| this._project.requestFileContent(this, contentLoaded.bind(this)); |
| |
| /** |
| * @param {?string} updatedContent |
| * @this {WebInspector.UISourceCode} |
| */ |
| function contentLoaded(updatedContent) |
| { |
| if (updatedContent === null) { |
| var workingCopy = this.workingCopy(); |
| this._commitContent("", false); |
| this.setWorkingCopy(workingCopy); |
| this._terminateContentCheck(); |
| return; |
| } |
| if (typeof this._lastAcceptedContent === "string" && this._lastAcceptedContent === updatedContent) { |
| this._terminateContentCheck(); |
| return; |
| } |
| if (this._content === updatedContent) { |
| delete this._lastAcceptedContent; |
| this._terminateContentCheck(); |
| return; |
| } |
| |
| if (!this.isDirty()) { |
| this._commitContent(updatedContent, false); |
| this._terminateContentCheck(); |
| return; |
| } |
| |
| var shouldUpdate = window.confirm(WebInspector.UIString("This file was changed externally. Would you like to reload it?")); |
| if (shouldUpdate) |
| this._commitContent(updatedContent, false); |
| else |
| this._lastAcceptedContent = updatedContent; |
| this._terminateContentCheck(); |
| } |
| }, |
| |
| /** |
| * @param {function(?string)} callback |
| */ |
| requestOriginalContent: function(callback) |
| { |
| this._project.requestFileContent(this, callback); |
| }, |
| |
| /** |
| * @param {string} content |
| * @param {boolean} shouldSetContentInProject |
| */ |
| _commitContent: function(content, shouldSetContentInProject) |
| { |
| delete this._lastAcceptedContent; |
| this._content = content; |
| this._contentLoaded = true; |
| |
| var lastRevision = this.history.length ? this.history[this.history.length - 1] : null; |
| if (!lastRevision || lastRevision._content !== this._content) { |
| var revision = new WebInspector.Revision(this, this._content, new Date()); |
| this.history.push(revision); |
| } |
| |
| this._innerResetWorkingCopy(); |
| this._hasCommittedChanges = true; |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.WorkingCopyCommitted); |
| if (this._url && WebInspector.fileManager.isURLSaved(this._url)) |
| this._saveURLWithFileManager(false, this._content); |
| if (shouldSetContentInProject) |
| this._project.setFileContent(this, this._content, function() { }); |
| }, |
| |
| /** |
| * @param {boolean} forceSaveAs |
| * @param {?string} content |
| */ |
| _saveURLWithFileManager: function(forceSaveAs, content) |
| { |
| WebInspector.fileManager.save(this._url, /** @type {string} */ (content), forceSaveAs, callback.bind(this)); |
| WebInspector.fileManager.close(this._url); |
| |
| /** |
| * @param {boolean} accepted |
| * @this {WebInspector.UISourceCode} |
| */ |
| function callback(accepted) |
| { |
| if (!accepted) |
| return; |
| this._savedWithFileManager = true; |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.SavedStateUpdated); |
| } |
| }, |
| |
| /** |
| * @param {boolean} forceSaveAs |
| */ |
| save: function(forceSaveAs) |
| { |
| if (this.project().type() === WebInspector.projectTypes.FileSystem || this.project().type() === WebInspector.projectTypes.Snippets) { |
| this.commitWorkingCopy(); |
| return; |
| } |
| if (this.isDirty()) { |
| this._saveURLWithFileManager(forceSaveAs, this.workingCopy()); |
| this.commitWorkingCopy(); |
| return; |
| } |
| this.requestContent(this._saveURLWithFileManager.bind(this, forceSaveAs)); |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| hasUnsavedCommittedChanges: function() |
| { |
| if (this._savedWithFileManager || this.project().canSetFileContent() || this._project.isServiceProject()) |
| return false; |
| if (this._project.workspace().hasResourceContentTrackingExtensions()) |
| return false; |
| return !!this._hasCommittedChanges; |
| }, |
| |
| /** |
| * @param {string} content |
| */ |
| addRevision: function(content) |
| { |
| this._commitContent(content, true); |
| }, |
| |
| revertToOriginal: function() |
| { |
| /** |
| * @this {WebInspector.UISourceCode} |
| * @param {?string} content |
| */ |
| function callback(content) |
| { |
| if (typeof content !== "string") |
| return; |
| |
| this.addRevision(content); |
| } |
| |
| this.requestOriginalContent(callback.bind(this)); |
| }, |
| |
| /** |
| * @param {function(!WebInspector.UISourceCode)} callback |
| */ |
| revertAndClearHistory: function(callback) |
| { |
| /** |
| * @this {WebInspector.UISourceCode} |
| * @param {?string} content |
| */ |
| function revert(content) |
| { |
| if (typeof content !== "string") |
| return; |
| |
| this.addRevision(content); |
| this.history = []; |
| callback(this); |
| } |
| |
| this.requestOriginalContent(revert.bind(this)); |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| workingCopy: function() |
| { |
| if (this._workingCopyGetter) { |
| this._workingCopy = this._workingCopyGetter(); |
| delete this._workingCopyGetter; |
| } |
| if (this.isDirty()) |
| return this._workingCopy; |
| return this._content; |
| }, |
| |
| resetWorkingCopy: function() |
| { |
| this._innerResetWorkingCopy(); |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.WorkingCopyChanged); |
| }, |
| |
| _innerResetWorkingCopy: function() |
| { |
| delete this._workingCopy; |
| delete this._workingCopyGetter; |
| }, |
| |
| /** |
| * @param {string} newWorkingCopy |
| */ |
| setWorkingCopy: function(newWorkingCopy) |
| { |
| this._workingCopy = newWorkingCopy; |
| delete this._workingCopyGetter; |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.WorkingCopyChanged); |
| }, |
| |
| setWorkingCopyGetter: function(workingCopyGetter) |
| { |
| this._workingCopyGetter = workingCopyGetter; |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.WorkingCopyChanged); |
| }, |
| |
| removeWorkingCopyGetter: function() |
| { |
| if (!this._workingCopyGetter) |
| return; |
| this._workingCopy = this._workingCopyGetter(); |
| delete this._workingCopyGetter; |
| }, |
| |
| commitWorkingCopy: function() |
| { |
| if (this.isDirty()) |
| this._commitContent(this.workingCopy(), true); |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| isDirty: function() |
| { |
| return typeof this._workingCopy !== "undefined" || typeof this._workingCopyGetter !== "undefined"; |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| highlighterType: function() |
| { |
| var lastIndexOfDot = this._name.lastIndexOf("."); |
| var extension = lastIndexOfDot !== -1 ? this._name.substr(lastIndexOfDot + 1) : ""; |
| var indexOfQuestionMark = extension.indexOf("?"); |
| if (indexOfQuestionMark !== -1) |
| extension = extension.substr(0, indexOfQuestionMark); |
| var mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extension.toLowerCase()]; |
| return mimeType || this.contentType().canonicalMimeType(); |
| }, |
| |
| /** |
| * @return {?string} |
| */ |
| content: function() |
| { |
| return this._content; |
| }, |
| |
| /** |
| * @param {string} query |
| * @param {boolean} caseSensitive |
| * @param {boolean} isRegex |
| * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback |
| */ |
| searchInContent: function(query, caseSensitive, isRegex, callback) |
| { |
| var content = this.content(); |
| if (content) { |
| var provider = new WebInspector.StaticContentProvider(this.contentType(), content); |
| provider.searchInContent(query, caseSensitive, isRegex, callback); |
| return; |
| } |
| |
| this._project.searchInFileContent(this, query, caseSensitive, isRegex, callback); |
| }, |
| |
| /** |
| * @param {?string} content |
| */ |
| _fireContentAvailable: function(content) |
| { |
| this._contentLoaded = true; |
| this._content = content; |
| |
| var callbacks = this._requestContentCallbacks.slice(); |
| this._requestContentCallbacks = []; |
| for (var i = 0; i < callbacks.length; ++i) |
| callbacks[i](content); |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| contentLoaded: function() |
| { |
| return this._contentLoaded; |
| }, |
| |
| /** |
| * @return {!Array.<!WebInspector.PresentationMessage>} |
| */ |
| consoleMessages: function() |
| { |
| return this._consoleMessages; |
| }, |
| |
| /** |
| * @param {!WebInspector.PresentationMessage} message |
| */ |
| consoleMessageAdded: function(message) |
| { |
| this._consoleMessages.push(message); |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.ConsoleMessageAdded, message); |
| }, |
| |
| /** |
| * @param {!WebInspector.PresentationMessage} message |
| */ |
| consoleMessageRemoved: function(message) |
| { |
| this._consoleMessages.remove(message); |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.ConsoleMessageRemoved, message); |
| }, |
| |
| consoleMessagesCleared: function() |
| { |
| this._consoleMessages = []; |
| this.dispatchEventToListeners(WebInspector.UISourceCode.Events.ConsoleMessagesCleared); |
| }, |
| |
| /** |
| * @param {number} lineNumber |
| * @param {number=} columnNumber |
| * @return {!WebInspector.UILocation} |
| */ |
| uiLocation: function(lineNumber, columnNumber) |
| { |
| if (typeof columnNumber === "undefined") |
| columnNumber = 0; |
| return new WebInspector.UILocation(this, lineNumber, columnNumber); |
| }, |
| |
| __proto__: WebInspector.Object.prototype |
| } |
| |
| /** |
| * @interface |
| */ |
| WebInspector.PresentationMessage = function() {} |
| |
| /** |
| * @constructor |
| * @param {!WebInspector.UISourceCode} uiSourceCode |
| * @param {number} lineNumber |
| * @param {number} columnNumber |
| */ |
| WebInspector.UILocation = function(uiSourceCode, lineNumber, columnNumber) |
| { |
| this.uiSourceCode = uiSourceCode; |
| this.lineNumber = lineNumber; |
| this.columnNumber = columnNumber; |
| } |
| |
| WebInspector.UILocation.prototype = { |
| /** |
| * @return {string} |
| */ |
| linkText: function() |
| { |
| var linkText = this.uiSourceCode.displayName(); |
| if (typeof this.lineNumber === "number") |
| linkText += ":" + (this.lineNumber + 1); |
| return linkText; |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| id: function() |
| { |
| return this.uiSourceCode.uri() + ":" + this.lineNumber + ":" + this.columnNumber; |
| }, |
| } |
| |
| /** |
| * @constructor |
| * @implements {WebInspector.ContentProvider} |
| * @param {!WebInspector.UISourceCode} uiSourceCode |
| * @param {?string|undefined} content |
| * @param {!Date} timestamp |
| */ |
| WebInspector.Revision = function(uiSourceCode, content, timestamp) |
| { |
| this._uiSourceCode = uiSourceCode; |
| this._content = content; |
| this._timestamp = timestamp; |
| } |
| |
| WebInspector.Revision.prototype = { |
| /** |
| * @return {!WebInspector.UISourceCode} |
| */ |
| get uiSourceCode() |
| { |
| return this._uiSourceCode; |
| }, |
| |
| /** |
| * @return {!Date} |
| */ |
| get timestamp() |
| { |
| return this._timestamp; |
| }, |
| |
| /** |
| * @return {?string} |
| */ |
| get content() |
| { |
| return this._content || null; |
| }, |
| |
| revertToThis: function() |
| { |
| /** |
| * @param {string} content |
| * @this {WebInspector.Revision} |
| */ |
| function revert(content) |
| { |
| if (this._uiSourceCode._content !== content) |
| this._uiSourceCode.addRevision(content); |
| } |
| this.requestContent(revert.bind(this)); |
| }, |
| |
| /** |
| * @return {string} |
| */ |
| contentURL: function() |
| { |
| return this._uiSourceCode.originURL(); |
| }, |
| |
| /** |
| * @return {!WebInspector.ResourceType} |
| */ |
| contentType: function() |
| { |
| return this._uiSourceCode.contentType(); |
| }, |
| |
| /** |
| * @param {function(string)} callback |
| */ |
| requestContent: function(callback) |
| { |
| callback(this._content || ""); |
| }, |
| |
| /** |
| * @param {string} query |
| * @param {boolean} caseSensitive |
| * @param {boolean} isRegex |
| * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback |
| */ |
| searchInContent: function(query, caseSensitive, isRegex, callback) |
| { |
| callback([]); |
| } |
| } |