Skip to content

Commit

Permalink
Merge 97223ab into d880685
Browse files Browse the repository at this point in the history
  • Loading branch information
linkesch committed Jul 21, 2016
2 parents d880685 + 97223ab commit a04c5b9
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 18 deletions.
61 changes: 61 additions & 0 deletions demo/absolute-container.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>medium editor | demo</title>
<link rel="stylesheet" href="css/demo.css">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.css">
<link rel="stylesheet" href="../dist/css/medium-editor.css">
<link rel="stylesheet" href="../dist/css/themes/default.css" id="medium-editor-theme">

<style>
body {
height: 100%;
}

#container {
position: absolute;
left: 50%;
margin-left: -480px;
height: 100%;
overflow: auto;
}
</style>
</head>
<body>
<a href="https://github.com/yabwe/medium-editor" class="github-link"><img style="z-index: 100;position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"></a>
<div class="top-bar">
Theme:
<select id="sel-themes">
<option value="themes/default" selected>default</option>
<option value="themes/roman">roman</option>
<option value="themes/mani">mani</option>
<option value="themes/flat">flat</option>
<option value="themes/bootstrap">bootstrap</option>
<option value="themes/tim">tim</option>
<option value="themes/beagle">beagle</option>
</select>
</div>
<div id="container">
<h1>Medium Editor</h1>
<div class="editable">
<p>My father’s family name being <a href="https://en.wikipedia.org/wiki/Pip_(Great_Expectations)">Pirrip</a>, and my Christian name Philip, my infant tongue could make of both names nothing longer or more explicit than Pip. So, I called myself Pip, and came to be called Pip.</p>
<p>I give Pirrip as my father’s family name, on the authority of his tombstone and my sister,—Mrs. Joe Gargery, who married the blacksmith. As I never saw my father or my mother, and never saw any likeness of either of them (for their days were long before the days of photographs), my first fancies regarding what they were like were unreasonably derived from their tombstones. The shape of the letters on my father’s, gave me an odd idea that he was a square, stout, dark man, with curly black hair. From the character and turn of the inscription, “Also Georgiana Wife of the Above,” I drew a childish conclusion that my mother was freckled and sickly. To five little stone lozenges, each about a foot and a half long, which were arranged in a neat row beside their grave, and were sacred to the memory of five little brothers of mine,—who gave up trying to get a living, exceedingly early in that universal struggle,—I am indebted for a belief I religiously entertained that they had all been born on their backs with their hands in their trousers-pockets, and had never taken them out in this state of existence.</p>
<p>Ours was the marsh country, down by the river, within, as the river wound, twenty miles of the sea. My first most vivid and broad impression of the identity of things seems to me to have been gained on a memorable raw afternoon towards evening. At such a time I found out for certain that this bleak place overgrown with nettles was the churchyard; and that Philip Pirrip, late of this parish, and also Georgiana wife of the above, were dead and buried; and that Alexander, Bartholomew, Abraham, Tobias, and Roger, infant children of the aforesaid, were also dead and buried; and that the dark flat wilderness beyond the churchyard, intersected with dikes and mounds and gates, with scattered cattle feeding on it, was the marshes; and that the low leaden line beyond was the river; and that the distant savage lair from which the wind was rushing was the sea; and that the small bundle of shivers growing afraid of it all and beginning to cry, was Pip.</p>
</div>
</div>
<p style="text-align: center;"><small><a style="color: #333;" target="_blank" href="http://www.goodreads.com/reader/475-great-expectations">Source</a></small></p>
<script src="../dist/js/medium-editor.js"></script>
<script>
var editor = new MediumEditor('.editable', {
buttonLabels: 'fontawesome',
elementsContainer: document.getElementById('container')
}),
cssLink = document.getElementById('medium-editor-theme');

document.getElementById('sel-themes').addEventListener('change', function () {
cssLink.href = '../dist/css/' + this.value + '.css';
});
</script>
</body>
</html>
34 changes: 34 additions & 0 deletions spec/anchor-preview.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,40 @@ describe('Anchor Preview TestCase', function () {

expect(document.querySelector('.medium-editor-anchor-preview')).toBeNull();
});

it('should correctly set preview position even if elementsContainer is absolute', function () {
var container = document.createElement('div'),
editor, anchorPreview;

container.style.position = 'absolute';
container.style.left = '100px';
container.style.top = '100px';
document.body.appendChild(container);

editor = this.newMediumEditor('.editor', {
elementsContainer: container,
anchorPreview: {
showWhenToolbarIsVisible: true
},
toolbar: {
static: true
}
});
anchorPreview = editor.getExtensionByName('anchor-preview').getPreviewElement();

selectElementContentsAndFire(editor.elements[0].firstChild);

// show preview
fireEvent(document.getElementById('test-link'), 'mouseover');

// preview shows only after delay
jasmine.clock().tick(1);
expect(anchorPreview.classList.contains('medium-editor-anchor-preview-active')).toBe(true);
expect(parseInt(anchorPreview.style.left, 10)).toBeLessThan(100);
expect(parseInt(anchorPreview.style.top, 10)).toBeLessThan(100);

document.body.removeChild(container);
});
});

});
24 changes: 24 additions & 0 deletions spec/toolbar.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,30 @@ describe('MediumEditor.extensions.toolbar TestCase', function () {
expect(toolbar.setToolbarButtonStates).toHaveBeenCalled();
expect(toolbar.showAndUpdateToolbar).toHaveBeenCalled();
});

it('should correctly update position even if elementsContainer is absolute', function () {
var container = document.createElement('div'),
editor, toolbar;

container.style.position = 'absolute';
container.style.left = '100px';
container.style.top = '100px';
document.body.appendChild(container);

this.el.innerHTML = 'lorem';

editor = this.newMediumEditor('.editor', {
elementsContainer: container
});
toolbar = editor.getExtensionByName('toolbar').getToolbarElement();

selectElementContentsAndFire(this.el);
expect(toolbar.classList.contains('medium-editor-toolbar-active')).toBe(true);
expect(parseInt(toolbar.style.left, 10)).toBeLessThan(100);
expect(parseInt(toolbar.style.top, 10)).toBeLessThan(100);

document.body.removeChild(container);
});
});

describe('Static Toolbars', function () {
Expand Down
37 changes: 31 additions & 6 deletions src/js/extensions/anchor-preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,15 @@

positionPreview: function (activeAnchor) {
activeAnchor = activeAnchor || this.activeAnchor;
var buttonHeight = this.anchorPreview.offsetHeight,
var containerWidth = this.window.innerWidth,
buttonHeight = this.anchorPreview.offsetHeight,
boundary = activeAnchor.getBoundingClientRect(),
middleBoundary = (boundary.left + boundary.right) / 2,
diffLeft = this.diffLeft,
diffTop = this.diffTop,
halfOffsetWidth,
defaultLeft;
elementsContainer = this.getEditorOption('elementsContainer'),
elementsContainerAbsolute = ['absolute', 'fixed'].indexOf(window.getComputedStyle(elementsContainer).getPropertyValue('position')) > -1,
relativeBoundary = {},
halfOffsetWidth, defaultLeft, middleBoundary, elementsContainerBoundary, top;

halfOffsetWidth = this.anchorPreview.offsetWidth / 2;
var toolbarExtension = this.base.getExtensionByName('toolbar');
Expand All @@ -119,12 +121,35 @@
}
defaultLeft = diffLeft - halfOffsetWidth;

this.anchorPreview.style.top = Math.round(buttonHeight + boundary.bottom - diffTop + this.window.pageYOffset - this.anchorPreview.offsetHeight) + 'px';
// If container element is absolute / fixed, recalculate boundaries to be relative to the container
if (elementsContainerAbsolute) {
elementsContainerBoundary = elementsContainer.getBoundingClientRect();
['top', 'left'].forEach(function (key) {
relativeBoundary[key] = boundary[key] - elementsContainerBoundary[key];
});

relativeBoundary.width = boundary.width;
relativeBoundary.height = boundary.height;
boundary = relativeBoundary;

containerWidth = elementsContainerBoundary.width;

// Adjust top position according to container scroll position
top = elementsContainer.scrollTop;
} else {
// Adjust top position according to window scroll position
top = this.window.pageYOffset;
}

middleBoundary = boundary.left + boundary.width / 2;
top += buttonHeight + boundary.top + boundary.height - diffTop - this.anchorPreview.offsetHeight;

this.anchorPreview.style.top = Math.round(top) + 'px';
this.anchorPreview.style.right = 'initial';
if (middleBoundary < halfOffsetWidth) {
this.anchorPreview.style.left = defaultLeft + halfOffsetWidth + 'px';
this.anchorPreview.style.right = 'initial';
} else if ((this.window.innerWidth - middleBoundary) < halfOffsetWidth) {
} else if ((containerWidth - middleBoundary) < halfOffsetWidth) {
this.anchorPreview.style.left = 'auto';
this.anchorPreview.style.right = 0;
} else {
Expand Down
55 changes: 43 additions & 12 deletions src/js/extensions/toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -616,35 +616,66 @@
}
}

var windowWidth = this.window.innerWidth,
middleBoundary = (boundary.left + boundary.right) / 2,
var containerWidth = this.window.innerWidth,
toolbarElement = this.getToolbarElement(),
toolbarHeight = toolbarElement.offsetHeight,
toolbarWidth = toolbarElement.offsetWidth,
halfOffsetWidth = toolbarWidth / 2,
buttonHeight = 50,
defaultLeft = this.diffLeft - halfOffsetWidth;
defaultLeft = this.diffLeft - halfOffsetWidth,
elementsContainer = this.getEditorOption('elementsContainer'),
elementsContainerAbsolute = ['absolute', 'fixed'].indexOf(window.getComputedStyle(elementsContainer).getPropertyValue('position')) > -1,
positions = {},
relativeBoundary = {},
middleBoundary, elementsContainerBoundary;

// If container element is absolute / fixed, recalculate boundaries to be relative to the container
if (elementsContainerAbsolute) {
elementsContainerBoundary = elementsContainer.getBoundingClientRect();
['top', 'left'].forEach(function (key) {
relativeBoundary[key] = boundary[key] - elementsContainerBoundary[key];
});

relativeBoundary.width = boundary.width;
relativeBoundary.height = boundary.height;
boundary = relativeBoundary;

containerWidth = elementsContainerBoundary.width;

// Adjust top position according to container scroll position
positions.top = elementsContainer.scrollTop;
} else {
// Adjust top position according to window scroll position
positions.top = this.window.pageYOffset;
}

middleBoundary = boundary.left + boundary.width / 2;
positions.top += boundary.top - toolbarHeight;

if (boundary.top < buttonHeight) {
toolbarElement.classList.add('medium-toolbar-arrow-over');
toolbarElement.classList.remove('medium-toolbar-arrow-under');
toolbarElement.style.top = buttonHeight + boundary.bottom - this.diffTop + this.window.pageYOffset - toolbarHeight + 'px';
positions.top += buttonHeight + boundary.height - this.diffTop;
} else {
toolbarElement.classList.add('medium-toolbar-arrow-under');
toolbarElement.classList.remove('medium-toolbar-arrow-over');
toolbarElement.style.top = boundary.top + this.diffTop + this.window.pageYOffset - toolbarHeight + 'px';
positions.top += this.diffTop;
}

if (middleBoundary < halfOffsetWidth) {
toolbarElement.style.left = defaultLeft + halfOffsetWidth + 'px';
toolbarElement.style.right = 'initial';
} else if ((windowWidth - middleBoundary) < halfOffsetWidth) {
toolbarElement.style.left = 'auto';
toolbarElement.style.right = 0;
positions.left = defaultLeft + halfOffsetWidth;
positions.right = 'initial';
} else if ((containerWidth - middleBoundary) < halfOffsetWidth) {
positions.left = 'auto';
positions.right = 0;
} else {
toolbarElement.style.left = defaultLeft + middleBoundary + 'px';
toolbarElement.style.right = 'initial';
positions.left = defaultLeft + middleBoundary;
positions.right = 'initial';
}

['top', 'left', 'right'].forEach(function (key) {
toolbarElement.style[key] = positions[key] + (isNaN(positions[key]) ? '' : 'px');
});
}
});

Expand Down

0 comments on commit a04c5b9

Please sign in to comment.