Home | History | Annotate | Download | only in settings
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /**
     32  * @constructor
     33  * @extends {WebInspector.DialogDelegate}
     34  * @param {string} fileSystemPath
     35  */
     36 WebInspector.EditFileSystemDialog = function(fileSystemPath)
     37 {
     38     WebInspector.DialogDelegate.call(this);
     39     this._fileSystemPath = fileSystemPath;
     40 
     41     this.element = document.createElementWithClass("div", "dialog-contents");
     42 
     43     var header = this.element.createChild("div", "header");
     44     var headerText = header.createChild("span");
     45     headerText.textContent = WebInspector.UIString("Edit file system");
     46 
     47     var closeButton = header.createChild("div", "close-button-gray done-button");
     48     closeButton.addEventListener("click", this._onDoneClick.bind(this), false);
     49 
     50     var contents = this.element.createChild("div", "contents");
     51 
     52     WebInspector.isolatedFileSystemManager.mapping().addEventListener(WebInspector.FileSystemMapping.Events.FileMappingAdded, this._fileMappingAdded, this);
     53     WebInspector.isolatedFileSystemManager.mapping().addEventListener(WebInspector.FileSystemMapping.Events.FileMappingRemoved, this._fileMappingRemoved, this);
     54     WebInspector.isolatedFileSystemManager.mapping().addEventListener(WebInspector.FileSystemMapping.Events.ExcludedFolderAdded, this._excludedFolderAdded, this);
     55     WebInspector.isolatedFileSystemManager.mapping().addEventListener(WebInspector.FileSystemMapping.Events.ExcludedFolderRemoved, this._excludedFolderRemoved, this);
     56 
     57     var blockHeader = contents.createChild("div", "block-header");
     58     blockHeader.textContent = WebInspector.UIString("Mappings");
     59     this._fileMappingsSection = contents.createChild("div", "section");
     60     this._fileMappingsListContainer = this._fileMappingsSection.createChild("div", "settings-list-container");
     61     var entries = WebInspector.isolatedFileSystemManager.mapping().mappingEntries(this._fileSystemPath);
     62 
     63     var urlColumn = { id: "url", placeholder: WebInspector.UIString("URL prefix") };
     64     var pathColumn = { id: "path", placeholder: WebInspector.UIString("Folder path") };
     65 
     66     this._fileMappingsList = new WebInspector.EditableSettingsList([urlColumn, pathColumn], this._fileMappingValuesProvider.bind(this), this._fileMappingValidate.bind(this), this._fileMappingEdit.bind(this));
     67     this._fileMappingsList.addEventListener(WebInspector.SettingsList.Events.Removed, this._fileMappingRemovedfromList.bind(this));
     68 
     69     this._fileMappingsList.element.classList.add("file-mappings-list");
     70     this._fileMappingsListContainer.appendChild(this._fileMappingsList.element);
     71 
     72     this._entries = {};
     73     for (var i = 0; i < entries.length; ++i)
     74         this._addMappingRow(entries[i]);
     75 
     76     blockHeader = contents.createChild("div", "block-header");
     77     blockHeader.textContent = WebInspector.UIString("Excluded folders");
     78     this._excludedFolderListSection = contents.createChild("div", "section excluded-folders-section");
     79     this._excludedFolderListContainer = this._excludedFolderListSection.createChild("div", "settings-list-container");
     80     var excludedFolderEntries = WebInspector.isolatedFileSystemManager.mapping().excludedFolders(fileSystemPath);
     81 
     82     this._excludedFolderList = new WebInspector.EditableSettingsList([pathColumn], this._excludedFolderValueProvider.bind(this), this._excludedFolderValidate.bind(this), this._excludedFolderEdit.bind(this));
     83     this._excludedFolderList.addEventListener(WebInspector.SettingsList.Events.Removed, this._excludedFolderRemovedfromList.bind(this));
     84     this._excludedFolderList.element.classList.add("excluded-folders-list");
     85     this._excludedFolderListContainer.appendChild(this._excludedFolderList.element);
     86     this._excludedFolderEntries = new StringMap();
     87     for (var i = 0; i < excludedFolderEntries.length; ++i)
     88         this._addExcludedFolderRow(excludedFolderEntries[i]);
     89 
     90     this.element.tabIndex = 0;
     91     this._hasMappingChanges = false;
     92 }
     93 
     94 WebInspector.EditFileSystemDialog.show = function(element, fileSystemPath)
     95 {
     96     WebInspector.Dialog.show(element, new WebInspector.EditFileSystemDialog(fileSystemPath));
     97     var glassPane = document.getElementById("glass-pane");
     98     glassPane.classList.add("settings-glass-pane");
     99 }
    100 
    101 WebInspector.EditFileSystemDialog.prototype = {
    102     /**
    103      * @param {!Element} element
    104      */
    105     show: function(element)
    106     {
    107         this._dialogElement = element;
    108         element.appendChild(this.element);
    109         element.classList.add("settings-dialog", "settings-tab");
    110     },
    111 
    112     _resize: function()
    113     {
    114         if (!this._dialogElement || !this._relativeToElement)
    115             return;
    116 
    117         const minWidth = 200;
    118         const minHeight = 150;
    119         var maxHeight = this._relativeToElement.offsetHeight - 10;
    120         maxHeight = Math.max(minHeight, maxHeight);
    121         var maxWidth = Math.min(540, this._relativeToElement.offsetWidth - 10);
    122         maxWidth = Math.max(minWidth, maxWidth);
    123         this._dialogElement.style.maxHeight = maxHeight + "px";
    124         this._dialogElement.style.width = maxWidth + "px";
    125 
    126         WebInspector.DialogDelegate.prototype.position(this._dialogElement, this._relativeToElement);
    127     },
    128 
    129     /**
    130      * @param {!Element} element
    131      * @param {!Element} relativeToElement
    132      */
    133     position: function(element, relativeToElement)
    134     {
    135         this._relativeToElement = relativeToElement;
    136         this._resize();
    137     },
    138 
    139     willHide: function(event)
    140     {
    141         if (!this._hasMappingChanges)
    142             return;
    143         if (window.confirm(WebInspector.UIString("It is recommended to restart DevTools after making these changes. Would you like to restart it?")))
    144             WebInspector.reload();
    145     },
    146 
    147     _fileMappingAdded: function(event)
    148     {
    149         var entry = /** @type {!WebInspector.FileSystemMapping.Entry} */ (event.data);
    150         this._addMappingRow(entry);
    151     },
    152 
    153     _fileMappingRemoved: function(event)
    154     {
    155         var entry = /** @type {!WebInspector.FileSystemMapping.Entry} */ (event.data);
    156         if (this._fileSystemPath !== entry.fileSystemPath)
    157             return;
    158         delete this._entries[entry.urlPrefix];
    159         if (this._fileMappingsList.itemForId(entry.urlPrefix))
    160             this._fileMappingsList.removeItem(entry.urlPrefix);
    161         this._resize();
    162     },
    163 
    164     /**
    165      * @param {string} itemId
    166      * @param {string} columnId
    167      * @return {string}
    168      */
    169     _fileMappingValuesProvider: function(itemId, columnId)
    170     {
    171         if (!itemId)
    172             return "";
    173         var entry = this._entries[itemId];
    174         switch (columnId) {
    175         case "url":
    176             return entry.urlPrefix;
    177         case "path":
    178             return entry.pathPrefix;
    179         default:
    180             console.assert("Should not be reached.");
    181         }
    182         return "";
    183     },
    184 
    185     /**
    186      * @param {?string} itemId
    187      * @param {!Object} data
    188      */
    189     _fileMappingValidate: function(itemId, data)
    190     {
    191         var oldPathPrefix = itemId ? this._entries[itemId].pathPrefix : null;
    192         return this._validateMapping(data["url"], itemId, data["path"], oldPathPrefix);
    193     },
    194 
    195     /**
    196      * @param {?string} itemId
    197      * @param {!Object} data
    198      */
    199     _fileMappingEdit: function(itemId, data)
    200     {
    201         if (itemId) {
    202             var urlPrefix = itemId;
    203             var pathPrefix = this._entries[itemId].pathPrefix;
    204             var fileSystemPath = this._entries[itemId].fileSystemPath;
    205             WebInspector.isolatedFileSystemManager.mapping().removeFileMapping(fileSystemPath, urlPrefix, pathPrefix);
    206         }
    207         this._addFileMapping(data["url"], data["path"]);
    208     },
    209 
    210     /**
    211      * @param {string} urlPrefix
    212      * @param {?string} allowedURLPrefix
    213      * @param {string} path
    214      * @param {?string} allowedPathPrefix
    215      */
    216     _validateMapping: function(urlPrefix, allowedURLPrefix, path, allowedPathPrefix)
    217     {
    218         var columns = [];
    219         if (!this._checkURLPrefix(urlPrefix, allowedURLPrefix))
    220             columns.push("url");
    221         if (!this._checkPathPrefix(path, allowedPathPrefix))
    222             columns.push("path");
    223         return columns;
    224     },
    225 
    226     /**
    227      * @param {!WebInspector.Event} event
    228      */
    229     _fileMappingRemovedfromList: function(event)
    230     {
    231         var urlPrefix = /** @type{?string} */ (event.data);
    232         if (!urlPrefix)
    233             return;
    234 
    235         var entry = this._entries[urlPrefix];
    236         WebInspector.isolatedFileSystemManager.mapping().removeFileMapping(entry.fileSystemPath, entry.urlPrefix, entry.pathPrefix);
    237         this._hasMappingChanges = true;
    238     },
    239 
    240     /**
    241      * @param {string} urlPrefix
    242      * @param {string} pathPrefix
    243      * @return {boolean}
    244      */
    245     _addFileMapping: function(urlPrefix, pathPrefix)
    246     {
    247         var normalizedURLPrefix = this._normalizePrefix(urlPrefix);
    248         var normalizedPathPrefix = this._normalizePrefix(pathPrefix);
    249         WebInspector.isolatedFileSystemManager.mapping().addFileMapping(this._fileSystemPath, normalizedURLPrefix, normalizedPathPrefix);
    250         this._hasMappingChanges = true;
    251         this._fileMappingsList.selectItem(normalizedURLPrefix);
    252         return true;
    253     },
    254 
    255     /**
    256      * @param {string} prefix
    257      * @return {string}
    258      */
    259     _normalizePrefix: function(prefix)
    260     {
    261         if (!prefix)
    262             return "";
    263         return prefix + (prefix[prefix.length - 1] === "/" ? "" : "/");
    264     },
    265 
    266     _addMappingRow: function(entry)
    267     {
    268         var fileSystemPath = entry.fileSystemPath;
    269         var urlPrefix = entry.urlPrefix;
    270         if (!this._fileSystemPath || this._fileSystemPath !== fileSystemPath)
    271             return;
    272 
    273         this._entries[urlPrefix] = entry;
    274         var fileMappingListItem = this._fileMappingsList.addItem(urlPrefix, null);
    275         this._resize();
    276     },
    277 
    278     _excludedFolderAdded: function(event)
    279     {
    280         var entry = /** @type {!WebInspector.FileSystemMapping.ExcludedFolderEntry} */ (event.data);
    281         this._addExcludedFolderRow(entry);
    282     },
    283 
    284     _excludedFolderRemoved: function(event)
    285     {
    286         var entry = /** @type {!WebInspector.FileSystemMapping.ExcludedFolderEntry} */ (event.data);
    287         var fileSystemPath = entry.fileSystemPath;
    288         if (!fileSystemPath || this._fileSystemPath !== fileSystemPath)
    289             return;
    290         delete this._excludedFolderEntries[entry.path];
    291         if (this._excludedFolderList.itemForId(entry.path))
    292             this._excludedFolderList.removeItem(entry.path);
    293     },
    294 
    295     /**
    296      * @param {string} itemId
    297      * @param {string} columnId
    298      * @return {string}
    299      */
    300     _excludedFolderValueProvider: function(itemId, columnId)
    301     {
    302         return itemId;
    303     },
    304 
    305     /**
    306      * @param {?string} itemId
    307      * @param {!Object} data
    308      */
    309     _excludedFolderValidate: function(itemId, data)
    310     {
    311         var fileSystemPath = this._fileSystemPath;
    312         var columns = [];
    313         if (!this._validateExcludedFolder(data["path"], itemId))
    314             columns.push("path");
    315         return columns;
    316     },
    317 
    318     /**
    319      * @param {string} path
    320      * @param {?string} allowedPath
    321      * @return {boolean}
    322      */
    323     _validateExcludedFolder: function(path, allowedPath)
    324     {
    325         return !!path && (path === allowedPath || !this._excludedFolderEntries.has(path));
    326     },
    327 
    328     /**
    329      * @param {?string} itemId
    330      * @param {!Object} data
    331      */
    332     _excludedFolderEdit: function(itemId, data)
    333     {
    334         var fileSystemPath = this._fileSystemPath;
    335         if (itemId)
    336             WebInspector.isolatedFileSystemManager.mapping().removeExcludedFolder(fileSystemPath, itemId);
    337         var excludedFolderPath = data["path"];
    338         WebInspector.isolatedFileSystemManager.mapping().addExcludedFolder(fileSystemPath, excludedFolderPath);
    339     },
    340 
    341     /**
    342      * @param {!WebInspector.Event} event
    343      */
    344     _excludedFolderRemovedfromList: function(event)
    345     {
    346         var itemId = /** @type{?string} */ (event.data);
    347         if (!itemId)
    348             return;
    349         WebInspector.isolatedFileSystemManager.mapping().removeExcludedFolder(this._fileSystemPath, itemId);
    350     },
    351 
    352     /**
    353      * @param {!WebInspector.FileSystemMapping.ExcludedFolderEntry} entry
    354      */
    355     _addExcludedFolderRow: function(entry)
    356     {
    357         var fileSystemPath = entry.fileSystemPath;
    358         if (!fileSystemPath || this._fileSystemPath !== fileSystemPath)
    359             return;
    360         var path = entry.path;
    361         this._excludedFolderEntries.set(path, entry);
    362         this._excludedFolderList.addItem(path, null);
    363         this._resize();
    364     },
    365 
    366     /**
    367      * @param {string} value
    368      * @param {?string} allowedPrefix
    369      * @return {boolean}
    370      */
    371     _checkURLPrefix: function(value, allowedPrefix)
    372     {
    373         var prefix = this._normalizePrefix(value);
    374         return !!prefix && (prefix === allowedPrefix || !this._entries[prefix]);
    375     },
    376 
    377     /**
    378      * @param {string} value
    379      * @param {?string} allowedPrefix
    380      * @return {boolean}
    381      */
    382     _checkPathPrefix: function(value, allowedPrefix)
    383     {
    384         var prefix = this._normalizePrefix(value);
    385         if (!prefix)
    386             return false;
    387         if (prefix === allowedPrefix)
    388             return true;
    389         for (var urlPrefix in this._entries) {
    390             var entry = this._entries[urlPrefix];
    391             if (urlPrefix && entry.pathPrefix === prefix)
    392                 return false;
    393         }
    394         return true;
    395     },
    396 
    397     focus: function()
    398     {
    399         WebInspector.setCurrentFocusElement(this.element);
    400     },
    401 
    402     _onDoneClick: function()
    403     {
    404         WebInspector.Dialog.hide();
    405     },
    406 
    407     onEnter: function()
    408     {
    409     },
    410 
    411     __proto__: WebInspector.DialogDelegate.prototype
    412 }
    413