Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #2285 from adobe/nj/issue-2221

Factor out width-resizing logic for inline widgets into the InlineWidget base class; use a cleaner pattern (and use it more consistently) for inheritance
  • Loading branch information...
commit 00c5e6d8000204425af83033411ff7a23afe6ebd 2 parents 41646b8 + 6b93be0
Peter Flynn peterflynn authored
5 src/command/Menus.js
View
@@ -728,8 +728,7 @@ define(function (require, exports, module) {
*
*/
function ContextMenu(id) {
- this.id = id;
- this.menu = new Menu(id);
+ Menu.apply(this, arguments);
var $newMenu = $("<li class='dropdown context-menu' id='" + StringUtils.jQueryIdEscape(id) + "'></li>"),
$popUp = $("<ul class='dropdown-menu'></ul>"),
@@ -748,7 +747,7 @@ define(function (require, exports, module) {
},
false);
}
- ContextMenu.prototype = new Menu();
+ ContextMenu.prototype = Object.create(Menu.prototype);
ContextMenu.prototype.constructor = ContextMenu;
ContextMenu.prototype.parentClass = Menu.prototype;
9 src/editor/InlineTextEditor.js
View
@@ -81,7 +81,7 @@ define(function (require, exports, module) {
/* @type {Array.<{Editor}>}*/
this.editors = [];
}
- InlineTextEditor.prototype = new InlineWidget();
+ InlineTextEditor.prototype = Object.create(InlineWidget.prototype);
InlineTextEditor.prototype.constructor = InlineTextEditor;
InlineTextEditor.prototype.parentClass = InlineWidget.prototype;
@@ -125,6 +125,8 @@ define(function (require, exports, module) {
* Called any time inline was closed, whether manually (via close()) or automatically
*/
InlineTextEditor.prototype.onClosed = function () {
+ InlineTextEditor.prototype.parentClass.onClosed.apply(this, arguments);
+
_syncGutterWidths(this.hostEditor);
this.editors.forEach(function (editor) {
@@ -170,6 +172,8 @@ define(function (require, exports, module) {
* editor is constructed and added to the DOM
*/
InlineTextEditor.prototype.onAdded = function () {
+ InlineTextEditor.prototype.parentClass.onAdded.apply(this, arguments);
+
this.editors.forEach(function (editor) {
editor.refresh();
});
@@ -260,7 +264,7 @@ define(function (require, exports, module) {
* @param {Editor} hostEditor
*/
InlineTextEditor.prototype.load = function (hostEditor) {
- this.hostEditor = hostEditor;
+ InlineTextEditor.prototype.parentClass.load.apply(this, arguments);
// TODO: incomplete impelementation. It's not clear yet if InlineTextEditor
// will fuction as an abstract class or as generic inline editor implementation
@@ -271,6 +275,7 @@ define(function (require, exports, module) {
* Called when the editor containing the inline is made visible.
*/
InlineTextEditor.prototype.onParentShown = function () {
+ InlineTextEditor.prototype.parentClass.onParentShown.apply(this, arguments);
// We need to call this explicitly whenever the host editor is reshown, since
// we don't actually resize the inline editor while its host is invisible (see
// isFullyVisible() check in sizeInlineWidgetToContents()).
37 src/editor/InlineWidget.js
View
@@ -51,6 +51,8 @@ define(function (require, exports, module) {
e.stopImmediatePropagation();
}
});
+
+ this.updateWidth = this.updateWidth.bind(this);
}
InlineWidget.prototype.htmlContent = null;
InlineWidget.prototype.$htmlContent = null;
@@ -64,6 +66,29 @@ define(function (require, exports, module) {
InlineWidget.prototype.height = 0;
/**
+ * Automatically updates the width of the inline editor when the parent editor's width changes due to
+ * edits or window resizes.
+ */
+ InlineWidget.prototype.updateWidth = function () {
+ // Set the minimum width of the widget (which doesn't include the padding) to the width
+ // of CodeMirror's linespace, so that the total width will be at least as large as the
+ // width of the host editor's code plus any internal padding required by the widget.
+ // We can't just set the min-width to 100% because that would be 100% of the clientWidth of
+ // the host editor, rather than the overall scroll width.
+ // We also can't just use the host editor's scrollWidth, because if the host editor's own
+ // content becomes less wide, our own width will continue to prop open the host editor's
+ // scrollWidth.
+ // So instead, we peg our width to the right edge of CodeMirror's lineSpace (which is its
+ // width plus its offset from the left edge of the $htmlContent container).
+ // If the lineSpace is less than the scroller's clientWidth, we want to use the clientWidth instead.
+ // This is a bit of a hack since it relies on knowing some detail about the innards of CodeMirror.
+ var lineSpace = this.hostEditor._getLineSpaceElement(),
+ scroller = this.hostEditor.getScrollerElement(),
+ minWidth = Math.max(scroller.clientWidth, $(lineSpace).offset().left - this.$htmlContent.offset().left + lineSpace.scrollWidth);
+ this.$htmlContent.css("min-width", minWidth + "px");
+ };
+
+ /**
* Closes this inline widget and all its contained Editors
*/
InlineWidget.prototype.close = function () {
@@ -76,7 +101,8 @@ define(function (require, exports, module) {
* Called any time inline is closed, whether manually or automatically
*/
InlineWidget.prototype.onClosed = function () {
- // do nothing - base implementation
+ $(this.hostEditor).off("change", this.updateWidth);
+ $(window).off("resize", this.updateWidth);
};
/**
@@ -84,7 +110,10 @@ define(function (require, exports, module) {
* focus or measuring content, which require htmlContent to be in the DOM tree.
*/
InlineWidget.prototype.onAdded = function () {
- // do nothing - base implementation
+ // Autosize the inline widget to the scrollable width of the main editor.
+ $(window).on("resize", this.updateWidth);
+ $(this.hostEditor).on("change", this.updateWidth);
+ window.setTimeout(this.updateWidth, 0);
};
/**
@@ -92,10 +121,6 @@ define(function (require, exports, module) {
*/
InlineWidget.prototype.load = function (hostEditor) {
this.hostEditor = hostEditor;
-
- // TODO: incomplete impelementation. It's not clear yet if InlineTextEditor
- // will fuction as an abstract class or as generic inline editor implementation
- // that just shows a range of text. See CSSInlineEditor.css for an implementation of load()
};
/**
24 src/editor/MultiRangeInlineEditor.js
View
@@ -95,7 +95,7 @@ define(function (require, exports, module) {
this._selectedRangeIndex = -1;
}
- MultiRangeInlineEditor.prototype = new InlineTextEditor();
+ MultiRangeInlineEditor.prototype = Object.create(InlineTextEditor.prototype);
MultiRangeInlineEditor.prototype.constructor = MultiRangeInlineEditor;
MultiRangeInlineEditor.prototype.parentClass = InlineTextEditor.prototype;
@@ -113,7 +113,7 @@ define(function (require, exports, module) {
*
*/
MultiRangeInlineEditor.prototype.load = function (hostEditor) {
- this.parentClass.load.call(this, hostEditor);
+ MultiRangeInlineEditor.prototype.parentClass.load.apply(this, arguments);
// Container to hold all editors
var self = this;
@@ -320,7 +320,7 @@ define(function (require, exports, module) {
*/
MultiRangeInlineEditor.prototype.onClosed = function () {
// Superclass onClosed() destroys editor
- this.parentClass.onClosed.call(this);
+ MultiRangeInlineEditor.prototype.parentClass.onClosed.apply(this, arguments);
// remove resize handlers for relatedContainer
$(this.hostEditor).off("change", this._updateRelatedContainer);
@@ -416,17 +416,6 @@ define(function (require, exports, module) {
// Add extra padding to the right edge of the widget to account for the range list.
this.$htmlContent.css("padding-right", this.$relatedContainer.outerWidth() + "px");
-
- // Set the minimum width of the widget (which doesn't include the padding) to the width
- // of CodeMirror's linespace, so that the total width will be at least as large as the
- // width of the host editor's code plus the padding for the range list. We need to do this
- // rather than just setting min-width to 100% because adding padding for the range list
- // actually pushes out the width of the container, so we would end up continuously
- // growing the overall width.
- // This is a bit of a hack since it relies on knowing some detail about the innards of CodeMirror.
- var lineSpace = this.hostEditor._getLineSpaceElement(),
- minWidth = $(lineSpace).offset().left - this.$htmlContent.offset().left + lineSpace.scrollWidth;
- this.$htmlContent.css("min-width", minWidth + "px");
};
/**
@@ -476,7 +465,7 @@ define(function (require, exports, module) {
// Ignore when the editor's content got lost due to a deleted file
if (cause && cause.type === "deleted") { return; }
// Else yield to the parent's implementation
- return this.parentClass._onLostContent.apply(this, arguments);
+ return MultiRangeInlineEditor.prototype.parentClass._onLostContent.apply(this, arguments);
};
/**
@@ -515,7 +504,8 @@ define(function (require, exports, module) {
*/
MultiRangeInlineEditor.prototype.sizeInlineWidgetToContents = function (force, ensureVisibility) {
// Size the code mirror editors height to the editor content
- this.parentClass.sizeInlineWidgetToContents.call(this, force);
+ // We use "call" rather than "apply" here since ensureVisibility was an argument added just for this override.
+ MultiRangeInlineEditor.prototype.parentClass.sizeInlineWidgetToContents.call(this, force);
// Size the widget height to the max between the editor content and the related ranges list
var widgetHeight = Math.max(this.$relatedContainer.find(".related").height(), this.$editorsDiv.height());
this.hostEditor.setInlineWidgetHeight(this, widgetHeight, ensureVisibility);
@@ -530,6 +520,7 @@ define(function (require, exports, module) {
* @override
*/
MultiRangeInlineEditor.prototype.refresh = function () {
+ MultiRangeInlineEditor.prototype.parentClass.refresh.apply(this, arguments);
this.sizeInlineWidgetToContents(true);
this._updateRelatedContainer();
this.editors.forEach(function (editor, j, arr) {
@@ -542,7 +533,6 @@ define(function (require, exports, module) {
* @returns {MultiRangeInlineEditor}
*/
function _getFocusedMultiRangeInlineEditor() {
-
var focusedMultiRangeInlineEditor = null,
result = EditorManager.getFocusedInlineWidget();
44 src/extensions/default/InlineColorEditor/InlineColorEditor.js
View
@@ -50,11 +50,7 @@ define(function (require, exports, module) {
this._handleColorChange = this._handleColorChange.bind(this);
this._handleHostDocumentChange = this._handleHostDocumentChange.bind(this);
- this._handleHostResize = this._handleHostResize.bind(this);
- $(window).on("resize", this._handleHostResize);
- window.setTimeout(this._handleHostResize, 0);
-
InlineWidget.call(this);
}
@@ -65,7 +61,7 @@ define(function (require, exports, module) {
*/
InlineColorEditor.COLOR_REGEX = /#[a-f0-9]{6}|#[a-f0-9]{3}|rgb\( ?\b([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b ?, ?\b([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b ?, ?\b([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b ?\)|rgba\( ?\b([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b ?, ?\b([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b ?, ?\b([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b ?, ?\b(1|0|0\.[0-9]{1,3}) ?\)|hsl\( ?\b([0-9]{1,2}|[12][0-9]{2}|3[0-5][0-9]|360)\b ?, ?\b([0-9]{1,2}|100)\b% ?, ?\b([0-9]{1,2}|100)\b% ?\)|hsla\( ?\b([0-9]{1,2}|[12][0-9]{2}|3[0-5][0-9]|360)\b ?, ?\b([0-9]{1,2}|100)\b% ?, ?\b([0-9]{1,2}|100)\b% ?, ?\b(1|0|0\.[0-9]{1,3}) ?\)/gi;
- InlineColorEditor.prototype = new InlineWidget();
+ InlineColorEditor.prototype = Object.create(InlineWidget.prototype);
InlineColorEditor.prototype.constructor = InlineColorEditor;
InlineColorEditor.prototype.parentClass = InlineWidget.prototype;
@@ -121,7 +117,7 @@ define(function (require, exports, module) {
// instead of two bookmarks to track the range. (In our current old version of
// CodeMirror v2, markText() isn't robust enough for this case.)
- var line = this.editor.document.getLine(start.line),
+ var line = this.hostEditor.document.getLine(start.line),
matches = line.substr(start.ch).match(InlineColorEditor.COLOR_REGEX);
// Note that end.ch is exclusive, so we don't need to add 1 before comparing to
@@ -129,7 +125,7 @@ define(function (require, exports, module) {
if (matches && (end.ch === undefined || end.ch - start.ch < matches[0].length)) {
end.ch = start.ch + matches[0].length;
this._endBookmark.clear();
- this._endBookmark = this.editor._codeMirror.setBookmark(end);
+ this._endBookmark = this.hostEditor._codeMirror.setBookmark(end);
}
if (end.ch === undefined) {
@@ -155,9 +151,9 @@ define(function (require, exports, module) {
if (!this._isHostChange) {
// Replace old color in code with the picker's color, and select it
this._isOwnChange = true;
- this.editor.document.replaceRange(colorString, range.start, range.end);
+ this.hostEditor.document.replaceRange(colorString, range.start, range.end);
this._isOwnChange = false;
- this.editor.setSelection(range.start, {
+ this.hostEditor.setSelection(range.start, {
line: range.start.line,
ch: range.start.ch + colorString.length
});
@@ -168,22 +164,14 @@ define(function (require, exports, module) {
};
/**
- * Update the width of the inline editor based on the host editor's width.
- */
- InlineColorEditor.prototype._handleHostResize = function () {
- this.$htmlContent.css("min-width", this.hostEditor.getScrollerElement().scrollWidth + "px");
- };
-
- /**
* @override
* @param {!Editor} hostEditor
*/
InlineColorEditor.prototype.load = function (hostEditor) {
- this.editor = hostEditor;
- this.parentClass.load.call(this, hostEditor);
+ InlineColorEditor.prototype.parentClass.load.apply(this, arguments);
// Create color picker control
- var allColorsInDoc = this.editor.document.getText().match(InlineColorEditor.COLOR_REGEX);
+ var allColorsInDoc = this.hostEditor.document.getText().match(InlineColorEditor.COLOR_REGEX);
var swatchInfo = this._collateColors(allColorsInDoc, MAX_USED_COLORS);
this.colorEditor = new ColorEditor(this.$htmlContent, this._color, this._handleColorChange, swatchInfo);
};
@@ -198,9 +186,9 @@ define(function (require, exports, module) {
* Perform sizing & focus once we've been added to Editor's DOM
*/
InlineColorEditor.prototype.onAdded = function () {
- this.parentClass.onAdded.call(this);
+ InlineColorEditor.prototype.parentClass.onAdded.apply(this, arguments);
- var doc = this.editor.document;
+ var doc = this.hostEditor.document;
doc.addRef();
$(doc).on("change", this._handleHostDocumentChange);
@@ -213,6 +201,8 @@ define(function (require, exports, module) {
* Called whenever the inline widget is closed, whether automatically or explicitly
*/
InlineColorEditor.prototype.onClosed = function () {
+ InlineColorEditor.prototype.parentClass.onClosed.apply(this, arguments);
+
if (this._startBookmark) {
this._startBookmark.clear();
}
@@ -220,13 +210,9 @@ define(function (require, exports, module) {
this._endBookmark.clear();
}
- var doc = this.editor.document;
+ var doc = this.hostEditor.document;
$(doc).off("change", this._handleHostDocumentChange);
doc.releaseRef();
-
- $(window).off("resize", this._handleHostResize);
-
- this.parentClass.onClosed.call(this);
};
InlineColorEditor.prototype._sizeEditorToContent = function () {
@@ -282,10 +268,6 @@ define(function (require, exports, module) {
* When text in the code editor changes, update color picker to reflect it
*/
InlineColorEditor.prototype._handleHostDocumentChange = function () {
- // Any host document change might change the scroll width, so we need to
- // recalculate our own width.
- this._handleHostResize();
-
// Don't push the change into the color editor if it came from the color editor.
if (this._isOwnChange) {
return;
@@ -293,7 +275,7 @@ define(function (require, exports, module) {
var range = this.getCurrentRange();
if (range) {
- var newColor = this.editor.document.getRange(range.start, range.end);
+ var newColor = this.hostEditor.document.getRange(range.start, range.end);
if (newColor !== this._color) {
this._isHostChange = true;
this.colorEditor.setColorFromString(newColor);
6 src/extensions/samples/InlineImageViewer/InlineImageViewer.js
View
@@ -39,7 +39,7 @@ define(function (require, exports, module) {
this.fullPath = fullPath;
InlineWidget.call(this);
}
- InlineImageViewer.prototype = new InlineWidget();
+ InlineImageViewer.prototype = Object.create(InlineWidget.prototype);
InlineImageViewer.prototype.constructor = InlineImageViewer;
InlineImageViewer.prototype.parentClass = InlineWidget.prototype;
@@ -49,7 +49,7 @@ define(function (require, exports, module) {
InlineImageViewer.prototype.$image = null;
InlineImageViewer.prototype.load = function (hostEditor) {
- this.parentClass.load.call(this, hostEditor);
+ InlineImageViewer.prototype.parentClass.load.apply(this, arguments);
this.$wrapperDiv = $(inlineEditorTemplate);
@@ -70,10 +70,12 @@ define(function (require, exports, module) {
};
InlineImageViewer.prototype.onAdded = function () {
+ InlineImageViewer.prototype.parentClass.onAdded.apply(this, arguments);
window.setTimeout(this._sizeEditorToContent.bind(this));
};
InlineImageViewer.prototype._sizeEditorToContent = function () {
+ // TODO: image might not be loaded yet--need to listen for load event and update then.
this.hostEditor.setInlineWidgetHeight(this, this.$wrapperDiv.height() + 20, true);
this.$image.css("opacity", 1);
};
12 src/file/NativeFileSystem.js
View
@@ -309,7 +309,9 @@ define(function (require, exports, module) {
NativeFileSystem.FileEntry = function (name, fs) {
NativeFileSystem.Entry.call(this, name, false, fs);
};
- NativeFileSystem.FileEntry.prototype = new NativeFileSystem.Entry();
+ NativeFileSystem.FileEntry.prototype = Object.create(NativeFileSystem.Entry.prototype);
+ NativeFileSystem.FileEntry.prototype.constructor = NativeFileSystem.FileEntry;
+ NativeFileSystem.FileEntry.prototype.parentClass = NativeFileSystem.Entry.prototype;
NativeFileSystem.FileEntry.prototype.toString = function () {
return "[FileEntry " + this.fullPath + "]";
@@ -429,7 +431,7 @@ define(function (require, exports, module) {
};
/**
- * Obtains the File objecte for a FileEntry object
+ * Obtains the File object for a FileEntry object
*
* @param {!function(File)} successCallback
* @param {!function(DOMError)} errorCallback
@@ -544,7 +546,9 @@ define(function (require, exports, module) {
// TODO (issue #241): void removeRecursively (VoidCallback successCallback, optional ErrorCallback errorCallback);
};
- NativeFileSystem.DirectoryEntry.prototype = new NativeFileSystem.Entry();
+ NativeFileSystem.DirectoryEntry.prototype = Object.create(NativeFileSystem.Entry.prototype);
+ NativeFileSystem.DirectoryEntry.prototype.constructor = NativeFileSystem.DirectoryEntry;
+ NativeFileSystem.DirectoryEntry.prototype.parentClass = NativeFileSystem.Entry.prototype;
NativeFileSystem.DirectoryEntry.prototype.toString = function () {
return "[DirectoryEntry " + this.fullPath + "]";
@@ -868,7 +872,7 @@ define(function (require, exports, module) {
this.onloadend = null;
};
// TODO (issue #241): extend EventTarget (draft status, not implememnted in webkit)
- // NativeFileSystem.FileReader.prototype = new NativeFileSystem.EventTarget()
+ // NativeFileSystem.FileReader.prototype = Object.create(NativeFileSystem.EventTarget.prototype);
NativeFileSystem.FileReader.prototype.readAsArrayBuffer = function (blob) {
// TODO (issue #241): implement
Please sign in to comment.
Something went wrong with that request. Please try again.