Skip to content

Commit 7c1edc6

Browse files
committed
Listen only to trusted events. Stop action event propagation by default. Make cursor styles important. Detect nonblocking elements when event is fired on their descendants. Use new event constructors. Version bump.
1 parent ea295a3 commit 7c1edc6

File tree

6 files changed

+264
-132
lines changed

6 files changed

+264
-132
lines changed

NonBlock.es5.js

Lines changed: 109 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
})(function () {
3232
var styling = document.createElement('style');
3333
styling.setAttribute('type', 'text/css');
34-
var css = '\n .nonblock{transition:opacity .3s ease;}\n .nonblock:hover{opacity:.1 !important;}\n .nonblock-hide{display:none !important;}\n .nonblock-cursor-auto{cursor:auto;}\n .nonblock-cursor-default{cursor:default;}\n .nonblock-cursor-none{cursor:none;}\n .nonblock-cursor-context-menu{cursor:context-menu;}\n .nonblock-cursor-help{cursor:help;}\n .nonblock-cursor-pointer{cursor:pointer;}\n .nonblock-cursor-progress{cursor:progress;}\n .nonblock-cursor-wait{cursor:wait;}\n .nonblock-cursor-cell{cursor:cell;}\n .nonblock-cursor-crosshair{cursor:crosshair;}\n .nonblock-cursor-text{cursor:text;}\n .nonblock-cursor-vertical-text{cursor:vertical-text;}\n .nonblock-cursor-alias{cursor:alias;}\n .nonblock-cursor-copy{cursor:copy;}\n .nonblock-cursor-move{cursor:move;}\n .nonblock-cursor-no-drop{cursor:no-drop;}\n .nonblock-cursor-not-allowed{cursor:not-allowed;}\n .nonblock-cursor-all-scroll{cursor:all-scroll;}\n .nonblock-cursor-col-resize{cursor:col-resize;}\n .nonblock-cursor-row-resize{cursor:row-resize;}\n .nonblock-cursor-n-resize{cursor:n-resize;}\n .nonblock-cursor-e-resize{cursor:e-resize;}\n .nonblock-cursor-s-resize{cursor:s-resize;}\n .nonblock-cursor-w-resize{cursor:w-resize;}\n .nonblock-cursor-ne-resize{cursor:ne-resize;}\n .nonblock-cursor-nw-resize{cursor:nw-resize;}\n .nonblock-cursor-se-resize{cursor:se-resize;}\n .nonblock-cursor-sw-resize{cursor:sw-resize;}\n .nonblock-cursor-ew-resize{cursor:ew-resize;}\n .nonblock-cursor-ns-resize{cursor:ns-resize;}\n .nonblock-cursor-nesw-resize{cursor:nesw-resize;}\n .nonblock-cursor-nwse-resize{cursor:nwse-resize;}\n .nonblock-cursor-zoom-in{cursor:zoom-in;}\n .nonblock-cursor-zoom-out{cursor:zoom-out;}\n .nonblock-cursor-grab{cursor:grab;}\n .nonblock-cursor-grabbing{cursor:grabbing;}\n ';
34+
var css = '\n .nonblock{transition:opacity .3s ease;}\n .nonblock:hover{opacity:.1 !important;}\n .nonblock-hide{display:none !important;}\n .nonblock-cursor-auto{cursor:auto !important;}\n .nonblock-cursor-default{cursor:default !important;}\n .nonblock-cursor-none{cursor:none !important;}\n .nonblock-cursor-context-menu{cursor:context-menu !important;}\n .nonblock-cursor-help{cursor:help !important;}\n .nonblock-cursor-pointer{cursor:pointer !important;}\n .nonblock-cursor-progress{cursor:progress !important;}\n .nonblock-cursor-wait{cursor:wait !important;}\n .nonblock-cursor-cell{cursor:cell !important;}\n .nonblock-cursor-crosshair{cursor:crosshair !important;}\n .nonblock-cursor-text{cursor:text !important;}\n .nonblock-cursor-vertical-text{cursor:vertical-text !important;}\n .nonblock-cursor-alias{cursor:alias !important;}\n .nonblock-cursor-copy{cursor:copy !important;}\n .nonblock-cursor-move{cursor:move !important;}\n .nonblock-cursor-no-drop{cursor:no-drop !important;}\n .nonblock-cursor-not-allowed{cursor:not-allowed !important;}\n .nonblock-cursor-all-scroll{cursor:all-scroll !important;}\n .nonblock-cursor-col-resize{cursor:col-resize !important;}\n .nonblock-cursor-row-resize{cursor:row-resize !important;}\n .nonblock-cursor-n-resize{cursor:n-resize !important;}\n .nonblock-cursor-e-resize{cursor:e-resize !important;}\n .nonblock-cursor-s-resize{cursor:s-resize !important;}\n .nonblock-cursor-w-resize{cursor:w-resize !important;}\n .nonblock-cursor-ne-resize{cursor:ne-resize !important;}\n .nonblock-cursor-nw-resize{cursor:nw-resize !important;}\n .nonblock-cursor-se-resize{cursor:se-resize !important;}\n .nonblock-cursor-sw-resize{cursor:sw-resize !important;}\n .nonblock-cursor-ew-resize{cursor:ew-resize !important;}\n .nonblock-cursor-ns-resize{cursor:ns-resize !important;}\n .nonblock-cursor-nesw-resize{cursor:nesw-resize !important;}\n .nonblock-cursor-nwse-resize{cursor:nwse-resize !important;}\n .nonblock-cursor-zoom-in{cursor:zoom-in !important;}\n .nonblock-cursor-zoom-out{cursor:zoom-out !important;}\n .nonblock-cursor-grab{cursor:grab !important;}\n .nonblock-cursor-grabbing{cursor:grabbing !important;}\n ';
3535
if (styling.styleSheet) {
3636
styling.styleSheet.cssText = css; // IE
3737
} else {
@@ -51,12 +51,23 @@
5151
regexUiEvents = /^(focus|blur|select|change|reset)$|^key(press|down|up)$/,
5252
regexHtmlEvents = /^(scroll|resize|(un)?load|abort|error)$/;
5353

54-
function isNonBlocking(el) {
55-
return el.classList.contains('nonblock');
54+
function getNonBlocking(el) {
55+
var nonblock = el;
56+
while (nonblock) {
57+
if (nonblock.classList && nonblock.classList.contains('nonblock')) {
58+
return nonblock;
59+
}
60+
nonblock = nonblock.parentNode;
61+
}
62+
return false;
5663
}
5764

5865
function isNotPropagating(el) {
59-
return el.classList.contains('nonblock-stoppropagation');
66+
return el.classList.contains('nonblock-stop-propagation');
67+
}
68+
69+
function isActionNotPropagating(el) {
70+
return !el.classList.contains('nonblock-allow-action-propagation');
6071
}
6172

6273
function getCursor(el) {
@@ -65,6 +76,9 @@
6576
}
6677

6778
function setCursor(el, value) {
79+
if (el.classList.contains('nonblock-cursor-' + value)) {
80+
return;
81+
}
6882
remCursor(el);
6983
el.classList.add('nonblock-cursor-' + value);
7084
}
@@ -78,93 +92,151 @@
7892
}
7993

8094
document.body.addEventListener('mouseenter', function (ev) {
81-
if (isNonBlocking(ev.target)) {
82-
nonBlockLastElem = ev.target;
83-
if (isNotPropagating(ev.target)) {
95+
var nonblock = void 0;
96+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target))) {
97+
nonBlockLastElem = nonblock;
98+
if (isNotPropagating(nonblock)) {
8499
ev.stopPropagation();
85100
}
86101
}
87102
}, true);
88103
document.body.addEventListener('mouseleave', function (ev) {
89-
if (isNonBlocking(ev.target)) {
90-
remCursor(ev.target);
104+
var nonblock = void 0;
105+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target))) {
106+
remCursor(nonblock);
91107
nonBlockLastElem = null;
92108
isSelectingText = false;
93-
if (isNotPropagating(ev.target)) {
109+
if (isNotPropagating(nonblock)) {
94110
ev.stopPropagation();
95111
}
96112
}
97113
}, true);
98114
document.body.addEventListener('mouseover', function (ev) {
99-
if (isNonBlocking(ev.target) && isNotPropagating(ev.target)) {
115+
var nonblock = void 0;
116+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target)) && isNotPropagating(nonblock)) {
100117
ev.stopPropagation();
101118
}
102119
}, true);
103120
document.body.addEventListener('mouseout', function (ev) {
104-
if (isNonBlocking(ev.target) && isNotPropagating(ev.target)) {
121+
var nonblock = void 0;
122+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target)) && isNotPropagating(nonblock)) {
105123
ev.stopPropagation();
106124
}
107125
}, true);
108126
document.body.addEventListener('mousemove', function (ev) {
109-
if (isNonBlocking(ev.target)) {
110-
nonblockPass(ev.target, ev, 'onmousemove');
127+
var nonblock = void 0;
128+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target))) {
129+
nonblockPass(nonblock, ev, 'onmousemove');
111130
// If the user just clicks somewhere, we don't want to select text, so this
112131
// detects that the user moved their mouse.
113132
if (isSelectingText === null) {
114133
window.getSelection().removeAllRanges();
115134
isSelectingText = true;
116135
}
117-
if (isNotPropagating(ev.target)) {
136+
if (isNotPropagating(nonblock)) {
118137
ev.stopPropagation();
119138
}
120139
}
121140
}, true);
122141
document.body.addEventListener('mousedown', function (ev) {
123-
if (isNonBlocking(ev.target)) {
124-
ev.preventDefault();
125-
nonblockPass(ev.target, ev, 'onmousedown');
142+
var nonblock = void 0;
143+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target))) {
144+
nonblockPass(nonblock, ev, 'onmousedown');
126145
isSelectingText = null;
127-
if (isNotPropagating(ev.target)) {
146+
if (isNotPropagating(nonblock) || isActionNotPropagating(nonblock)) {
128147
ev.stopPropagation();
129148
}
130149
}
131150
}, true);
132151
document.body.addEventListener('mouseup', function (ev) {
133-
if (isNonBlocking(ev.target)) {
134-
ev.preventDefault();
135-
nonblockPass(ev.target, ev, 'onmouseup');
152+
var nonblock = void 0;
153+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target))) {
154+
nonblockPass(nonblock, ev, 'onmouseup');
136155
if (isSelectingText === null) {
137156
window.getSelection().removeAllRanges();
138157
}
139158
isSelectingText = false;
140-
if (isNotPropagating(ev.target)) {
159+
if (isNotPropagating(nonblock) || isActionNotPropagating(nonblock)) {
141160
ev.stopPropagation();
142161
}
143162
}
144163
}, true);
145164
document.body.addEventListener('click', function (ev) {
146-
if (isNonBlocking(ev.target)) {
147-
nonblockPass(ev.target, ev, 'onclick');
148-
if (isNotPropagating(ev.target)) {
165+
var nonblock = void 0;
166+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target))) {
167+
nonblockPass(nonblock, ev, 'onclick');
168+
if (isNotPropagating(nonblock) || isActionNotPropagating(nonblock)) {
149169
ev.stopPropagation();
150170
}
151171
}
152172
}, true);
153173
document.body.addEventListener('dblclick', function (ev) {
154-
if (isNonBlocking(ev.target)) {
155-
nonblockPass(ev.target, ev, 'ondblclick');
156-
if (isNotPropagating(ev.target)) {
174+
var nonblock = void 0;
175+
if (ev.isTrusted && (nonblock = getNonBlocking(ev.target))) {
176+
nonblockPass(nonblock, ev, 'ondblclick');
177+
if (isNotPropagating(nonblock) || isActionNotPropagating(nonblock)) {
157178
ev.stopPropagation();
158179
}
159180
}
160181
}, true);
161182

162183
// Fire a DOM event.
184+
var useEventConstructors = true;
185+
try {
186+
var e = new MouseEvent('click');
187+
} catch (e) {
188+
useEventConstructors = false;
189+
}
163190
var domEvent = function domEvent(elem, event, origEvent, bubbles) {
164191
var eventObject = void 0;
165192
event = event.toLowerCase();
166-
if (document.createEvent && elem.dispatchEvent) {
167-
// FireFox, Opera, Safari, Chrome
193+
if (useEventConstructors) {
194+
// New browsers
195+
event = event.replace(regexOn, '');
196+
if (event.match(regexMouseEvents)) {
197+
eventObject = new MouseEvent(event, {
198+
screenX: origEvent.screenX,
199+
screenY: origEvent.screenY,
200+
clientX: origEvent.clientX,
201+
clientY: origEvent.clientY,
202+
ctrlKey: origEvent.ctrlKey,
203+
shiftKey: origEvent.shiftKey,
204+
altKey: origEvent.altKey,
205+
metaKey: origEvent.metaKey,
206+
button: origEvent.button,
207+
buttons: origEvent.buttons,
208+
relatedTarget: origEvent.relatedTarget,
209+
region: origEvent.region,
210+
211+
detail: origEvent.detail,
212+
view: origEvent.view,
213+
214+
bubbles: bubbles === undefined ? origEvent.bubbles : bubbles,
215+
cancelable: origEvent.cancelable,
216+
composed: origEvent.composed
217+
});
218+
} else if (event.match(regexUiEvents)) {
219+
eventObject = new UIEvent(event, {
220+
detail: origEvent.detail,
221+
view: origEvent.view,
222+
223+
bubbles: bubbles === undefined ? origEvent.bubbles : bubbles,
224+
cancelable: origEvent.cancelable,
225+
composed: origEvent.composed
226+
});
227+
} else if (event.match(regexHtmlEvents)) {
228+
eventObject = new Event(event, {
229+
bubbles: bubbles === undefined ? origEvent.bubbles : bubbles,
230+
cancelable: origEvent.cancelable,
231+
composed: origEvent.composed
232+
});
233+
}
234+
if (!eventObject) {
235+
return;
236+
}
237+
elem.dispatchEvent(eventObject);
238+
} else if (document.createEvent && elem.dispatchEvent) {
239+
// Old method for FireFox, Opera, Safari, Chrome
168240
event = event.replace(regexOn, '');
169241
if (event.match(regexMouseEvents)) {
170242
// This allows the click event to fire on the notice. There is
@@ -181,7 +253,7 @@
181253
}
182254
if (!eventObject) {
183255
return;
184-
};
256+
}
185257
elem.dispatchEvent(eventObject);
186258
} else {
187259
// Internet Explorer
@@ -204,12 +276,12 @@
204276
offset = void 0;
205277
if (document.caretPositionFromPoint) {
206278
range = document.caretPositionFromPoint(event.clientX, event.clientY);
207-
textNode = range.offsetNode;
208-
offset = range.offset;
279+
textNode = range ? range.offsetNode : null;
280+
offset = range ? range.offset : null;
209281
} else if (document.caretRangeFromPoint) {
210282
range = document.caretRangeFromPoint(event.clientX, event.clientY);
211-
textNode = range.startContainer;
212-
offset = range.startOffset;
283+
textNode = range ? range.startContainer : null;
284+
offset = range ? range.startOffset : null;
213285
}
214286
if (range) {
215287
whitespaceBefore = range.startContainer.textContent.match(/^[\s\n]*/)[0];
@@ -221,7 +293,7 @@
221293
isOverTextNode = false;
222294
if (cursorStyle === 'auto' && elBelow.tagName === 'A') {
223295
cursorStyle = 'pointer';
224-
} else if ((!whitespaceBefore.length || offset > whitespaceBefore.length) && offset < text.length) {
296+
} else if (range && (!whitespaceBefore.length || offset > whitespaceBefore.length) && offset < text.length) {
225297
if (cursorStyle === 'auto') {
226298
cursorStyle = 'text';
227299
}

0 commit comments

Comments
 (0)