Skip to content

Commit

Permalink
Ticket #134 #223 - Now the focus() method is working across browsers.…
Browse files Browse the repository at this point in the history
… Removed

is() support since it was turning out to be too much work. It's now it's own
ticket (#229).

This fixes the IE9/10 issue where the editor was not focused so you could
keep typing after switching over to the preview() (through clicking the icons
or doing a key command).
  • Loading branch information
OscarGodson committed May 17, 2013
1 parent 21766af commit 82051ae
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 53 deletions.
13 changes: 1 addition & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ Returns a boolean for the requested state. Useful when you need to know if the e
* `edit`
* `preview`
* `fullscreen`
* `focused`

```javascript
fullscreenBtn.onclick = function () {
Expand Down Expand Up @@ -396,7 +395,7 @@ and also will focus on the visible view (edit or preview).

```
showEditorBtn.onclick = function () {
editorWrapper.style.display = 'block'; // switch from being display:none
editorWrapper.style.display = 'block'; // switch from being hidden from the user
editor.focus(); // Focus and allow user to start editing right away
}
```
Expand Down Expand Up @@ -498,16 +497,6 @@ created, removed, or updated. Below is a complete list of currently supported ev
<td><code>edit</code></td>
<td>Fires whenever the editor is opened (excluding fullscreen) via <code>edit()</code> or the edit button.</td>
</tr>
<!-- Soon.
<tr>
<td><code>focus</code></td>
<td>Fires whenever the editor is focused <code>focus()</code> or other means.</td>
</tr>
<tr>
<td><code>blur</code></td>
<td>Fires whenever the editor is blurred.</td>
</tr>
-->
<tr>
<td><code>fullscreenenter</code></td>
<td>Fires whenever the editor opens in fullscreen via <code>fullscreen()</code> or the fullscreen button.</td>
Expand Down
50 changes: 37 additions & 13 deletions epiceditor/js/epiceditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@
, eventableIframes
, i; // i is reused for loops

// Startup is a way to check if this EpicEditor is starting up. Useful for
// checking and doing certain things before EpicEditor emits a load event.
self._eeState.startup = true;

if (self.settings.useNativeFullscreen) {
nativeFsWebkit = document.body.webkitRequestFullScreen ? true : false;
nativeFsMoz = document.body.mozRequestFullScreen ? true : false;
Expand Down Expand Up @@ -606,7 +610,7 @@
// iframe's ready state == complete, then we can focus on the contenteditable
self.iframe.addEventListener('readystatechange', function () {
if (self.iframe.readyState == 'complete') {
self.focus(true);
self.focus();
}
});
}
Expand Down Expand Up @@ -969,6 +973,7 @@
}

self.iframe.close();
self._eeState.startup = false;
// The callback and call are the same thing, but different ways to access them
callback.call(this);
this.emit('load');
Expand All @@ -994,7 +999,7 @@
_syncTextarea = function () {
self._textareaElement.value = self.exportFile(textareaFileName, 'text', true);
}

if (typeof self.settings.textarea == 'string') {
self._textareaElement = document.getElementById(self.settings.textarea);
}
Expand All @@ -1017,7 +1022,7 @@
// the local file in localStorage's modified date is newer than the server.
if (self._textareaElement.value !== '') {
self.importFile(textareaFileName, self._textareaElement.value);

// manually save draft after import so there is no delay between the
// import and exporting in _syncTextarea. Without this, _syncTextarea
// will pull the saved data from localStorage which will be <=100ms old.
Expand All @@ -1031,6 +1036,23 @@
self.on('__update', _syncTextarea);
}

/**
* Will NOT focus the editor if the editor is still starting up AND
* focusOnLoad is set to false. This allows you to place this in code that
* gets fired during .load() without worrying about it overriding the user's
* option. For example use cases see preview() and edit().
* @returns {undefined}
*/

// Prevent focus when the user sets focusOnLoad to false by checking if the
// editor is starting up AND if focusOnLoad is true
EpicEditor.prototype._focusExceptOnLoad = function () {
var self = this;
if ((self._eeState.startup && self.settings.focusOnLoad) || !self._eeState.startup) {
self.focus();
}
}

/**
* Will remove the editor, but not offline files
* @returns {object} EpicEditor will be returned
Expand Down Expand Up @@ -1163,7 +1185,7 @@
self.previewerIframe.style.display = 'block';
self._eeState.preview = true;
self._eeState.edit = false;
self.focus();
self._focusExceptOnLoad();
}

self.emit('preview');
Expand All @@ -1174,20 +1196,18 @@
* Helper to focus on the editor iframe. Will figure out which iframe to
* focus on based on which one is active and will handle the cross browser
* issues with focusing on the iframe vs the document body.
* @param {boolean} pageload If you want to focus on page load you need to
* set this as true (just for Firefox for some reason).
* @returns {object} EpicEditor will be returned
*/
EpicEditor.prototype.focus = function (pageload) {
var self = this
, focusElement = self.is('preview') ? self.previewerIframeDocument.body
, isPreview = self.is('preview')
, focusElement = isPreview ? self.previewerIframeDocument.body
: self.editorIframeDocument.body;
// I don't know why this is required but it is for Firefox. If it's a fresh
// page load iframe focus you need to focus on the body, but otherwise,
// Firefox likes to focus on the iframes directly.
if (_isFirefox() && !pageload) {
focusElement = self.is('preview') ? self.previewerIframe : self.editorIframe;

if (_isFirefox() && isPreview) {
focusElement = self.previewerIframe;
}

focusElement.focus();
return this;
}
Expand Down Expand Up @@ -1223,7 +1243,7 @@
self._eeState.edit = true;
self.editorIframe.style.display = 'block';
self.previewerIframe.style.display = 'none';
self.focus();
self._focusExceptOnLoad();
self.emit('edit');
return this;
}
Expand Down Expand Up @@ -1272,6 +1292,10 @@
return self._eeState.edit;
case 'fullscreen':
return self._eeState.fullscreen;
// TODO: This "works", but the tests are saying otherwise. Come back to this
// and figure out how to fix it.
// case 'focused':
// return document.activeElement == self.iframeElement;
default:
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion epiceditor/js/epiceditor.min.js

Large diffs are not rendered by default.

13 changes: 1 addition & 12 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,6 @@ <h3>is(<em>state</em>)</h3>
<li><code>edit</code></li>
<li><code>preview</code></li>
<li><code>fullscreen</code></li>
<li><code>focused</code></li>
</ul>
<pre><code class="lang-javascript">fullscreenBtn.onclick = function () {
if (!editor.is(&#39;loaded&#39;)) { return; }
Expand Down Expand Up @@ -352,7 +351,7 @@ <h3>focus()</h3>

</p>
<pre><code>showEditorBtn.onclick = function () {
editorWrapper.style.display = &#39;block&#39;; // switch from being display:none
editorWrapper.style.display = &#39;block&#39;; // switch from being hidden from the user
editor.focus(); // Focus and allow user to start editing right away
}</code></pre>
<h3>enterFullscreen()</h3>
Expand Down Expand Up @@ -447,16 +446,6 @@ <h2>Events</h2>
<td><code>edit</code></td>
<td>Fires whenever the editor is opened (excluding fullscreen) via <code>edit()</code> or the edit button.</td>
</tr>
<!-- Soon.
<tr>
<td><code>focus</code></td>
<td>Fires whenever the editor is focused <code>focus()</code> or other means.</td>
</tr>
<tr>
<td><code>blur</code></td>
<td>Fires whenever the editor is blurred.</td>
</tr>
-->
<tr>
<td><code>fullscreenenter</code></td>
<td>Fires whenever the editor opens in fullscreen via <code>fullscreen()</code> or the fullscreen button.</td>
Expand Down
50 changes: 37 additions & 13 deletions src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@
, eventableIframes
, i; // i is reused for loops

// Startup is a way to check if this EpicEditor is starting up. Useful for
// checking and doing certain things before EpicEditor emits a load event.
self._eeState.startup = true;

if (self.settings.useNativeFullscreen) {
nativeFsWebkit = document.body.webkitRequestFullScreen ? true : false;
nativeFsMoz = document.body.mozRequestFullScreen ? true : false;
Expand Down Expand Up @@ -606,7 +610,7 @@
// iframe's ready state == complete, then we can focus on the contenteditable
self.iframe.addEventListener('readystatechange', function () {
if (self.iframe.readyState == 'complete') {
self.focus(true);
self.focus();
}
});
}
Expand Down Expand Up @@ -969,6 +973,7 @@
}

self.iframe.close();
self._eeState.startup = false;
// The callback and call are the same thing, but different ways to access them
callback.call(this);
this.emit('load');
Expand All @@ -994,7 +999,7 @@
_syncTextarea = function () {
self._textareaElement.value = self.exportFile(textareaFileName, 'text', true);
}

if (typeof self.settings.textarea == 'string') {
self._textareaElement = document.getElementById(self.settings.textarea);
}
Expand All @@ -1017,7 +1022,7 @@
// the local file in localStorage's modified date is newer than the server.
if (self._textareaElement.value !== '') {
self.importFile(textareaFileName, self._textareaElement.value);

// manually save draft after import so there is no delay between the
// import and exporting in _syncTextarea. Without this, _syncTextarea
// will pull the saved data from localStorage which will be <=100ms old.
Expand All @@ -1031,6 +1036,23 @@
self.on('__update', _syncTextarea);
}

/**
* Will NOT focus the editor if the editor is still starting up AND
* focusOnLoad is set to false. This allows you to place this in code that
* gets fired during .load() without worrying about it overriding the user's
* option. For example use cases see preview() and edit().
* @returns {undefined}
*/

// Prevent focus when the user sets focusOnLoad to false by checking if the
// editor is starting up AND if focusOnLoad is true
EpicEditor.prototype._focusExceptOnLoad = function () {
var self = this;
if ((self._eeState.startup && self.settings.focusOnLoad) || !self._eeState.startup) {
self.focus();
}
}

/**
* Will remove the editor, but not offline files
* @returns {object} EpicEditor will be returned
Expand Down Expand Up @@ -1163,7 +1185,7 @@
self.previewerIframe.style.display = 'block';
self._eeState.preview = true;
self._eeState.edit = false;
self.focus();
self._focusExceptOnLoad();
}

self.emit('preview');
Expand All @@ -1174,20 +1196,18 @@
* Helper to focus on the editor iframe. Will figure out which iframe to
* focus on based on which one is active and will handle the cross browser
* issues with focusing on the iframe vs the document body.
* @param {boolean} pageload If you want to focus on page load you need to
* set this as true (just for Firefox for some reason).
* @returns {object} EpicEditor will be returned
*/
EpicEditor.prototype.focus = function (pageload) {
var self = this
, focusElement = self.is('preview') ? self.previewerIframeDocument.body
, isPreview = self.is('preview')
, focusElement = isPreview ? self.previewerIframeDocument.body
: self.editorIframeDocument.body;
// I don't know why this is required but it is for Firefox. If it's a fresh
// page load iframe focus you need to focus on the body, but otherwise,
// Firefox likes to focus on the iframes directly.
if (_isFirefox() && !pageload) {
focusElement = self.is('preview') ? self.previewerIframe : self.editorIframe;

if (_isFirefox() && isPreview) {
focusElement = self.previewerIframe;
}

focusElement.focus();
return this;
}
Expand Down Expand Up @@ -1223,7 +1243,7 @@
self._eeState.edit = true;
self.editorIframe.style.display = 'block';
self.previewerIframe.style.display = 'none';
self.focus();
self._focusExceptOnLoad();
self.emit('edit');
return this;
}
Expand Down Expand Up @@ -1272,6 +1292,10 @@
return self._eeState.edit;
case 'fullscreen':
return self._eeState.fullscreen;
// TODO: This "works", but the tests are saying otherwise. Come back to this
// and figure out how to fix it.
// case 'focused':
// return document.activeElement == self.iframeElement;
default:
return false;
}
Expand Down
33 changes: 33 additions & 0 deletions test/test.focus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*global createContainer:false, removeContainer:false, rnd:false */

describe('.focus()', function () {
var testEl
, id
, editor;

beforeEach(function () {
id = rnd();
testEl = createContainer(id);
editor = new EpicEditor({
basePath: '/epiceditor/',
container: testEl,
focusOnLoad: false
});
editor.load();
});

afterEach(function () {
editor.removeListener('focus');
editor.removeListener('blur');
editor.unload();
removeContainer(id);
});

it('should focus the editor', function () {
document.querySelector('a').focus();
expect(document.activeElement.nodeName).to.be('A');
editor.focus();
// Use .id to compare. A direct obj to obj comparison takes Mocha a long time
expect(document.activeElement.id).to.be(editor.getElement('wrapperIframe').id);
});
});
14 changes: 13 additions & 1 deletion test/test.is.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*global createContainer:false, removeContainer:false, rnd:false */
/*global createContainer:false, removeContainer:false, rnd:false, xit:false */

describe('.is(state)', function () {
var testEl
Expand Down Expand Up @@ -68,6 +68,18 @@ describe('.is(state)', function () {
expect(editor.is('fullscreen')).to.be(false);
});

xit('should return focus:TRUE when the editor is focused', function () {
expect(editor.is('focused')).to.be(false);
editor.focus();
expect(editor.is('focused')).to.be(true);
});

xit('should return focus:FALSE when the editor is NOT focused', function () {
// Make sure we focus on something else to be sure the editor isn't focused
document.querySelector('a').focus();
expect(editor.is('focused')).to.be(false);
});

it('should return undefined:FALSE for undefined states', function () {
expect(editor.is('undefined')).to.be(false);
});
Expand Down
4 changes: 3 additions & 1 deletion test/tests.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
color: green;
}
.hidden {
display: none;
position: absolute !important;
left: -9999999px !important;
}
#mocha .test.fail code {
color: #fff;
Expand Down Expand Up @@ -48,6 +49,7 @@
<script src="test.save.js"></script>
<script src="test.unload.js"></script>
<script src="test.reflow.js"></script>
<script src="test.focus.js"></script>

<script>
$(function() {
Expand Down

0 comments on commit 82051ae

Please sign in to comment.