├── .gitignore ├── .htaccess ├── LICENSE ├── README.md ├── bower.json ├── gulpfile.js ├── icon.png ├── index.css ├── index.html ├── package.json ├── php ├── Parsedown.php └── index.php ├── scroll-scope.js ├── scroll-scope.min.js └── splash.png /.gitignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .DS_Store 3 | .idea 4 | .project 5 | *.log 6 | 7 | node_modules/ 8 | vendor/ 9 | bower_components/ 10 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | # Set the default handler. 2 | DirectoryIndex index.php index.html index.htm 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jerry Jäppinen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # *scroll-scope.js* 3 | 4 | Small jQuery plugin to **keep parent element still when scrolling an element to its boundary**. 5 | 6 | Commonly in scroll interaction, user hovers a mouse cursor over a scrollable element and uses trackpad or mouse wheel to scroll the element. When an element reaches its boundary, its parent element continues scrolling. Usually this means that the user will continue moving down the page when attempting to interact with an specific container. This is a common issue with dropdown menus and modal dialogs. 7 | 8 | This behavior is most prevalent in desktop browsers. To fix this problem that shouldn't even exist, scroll-scope.js exists. 9 | 10 | See project home and demos on [eiskis.net/scroll-scope](http://eiskis.net/scroll-scope). 11 | 12 | ## Get the plugin 13 | 14 | Current version is *0.1.0*. 15 | 16 | - [scroll-scope.js](https://raw.githubusercontent.com/Eiskis/scroll-scope/master/scroll-scope.js) 17 | - [scroll-scope.min.js](https://raw.githubusercontent.com/Eiskis/scroll-scope/master/scroll-scope.min.js) 18 | 19 | Install with Bower: 20 | 21 | ```sh 22 | bower install scroll-scope 23 | ``` 24 | 25 | File [issues or pull requests](https://github.com/Eiskis/scroll-scope/issues) to share potential improvements. The plugin is released under MIT. Source is available on [GitHub](https://github.com/Eiskis/scroll-scope). To contribute, clone the repo, make changes in *scroll-scope.js* and build the minified version with `gulp`. 26 | 27 | 28 | 29 | ## Usage 30 | 31 | Add the `data-scroll-scope` attribute to any scrollable element on the page: 32 | 33 | ```html 34 | 35 |
force
on and off during runtime if you please.
55 |
56 |
57 |
58 | ### Options
59 |
60 | You can change which elements and events are targeted by setting them upon initialization. Note that having events listed here does not mean they're blocked automatically, rather the plugin listens to these events and evaluates them when encountered.
61 |
62 | Here are the defaults:
63 |
64 | ```js
65 | $(document).scrollScope({
66 | elements: '[data-scroll-scope]',
67 | forcedElements: '[data-scroll-scope="force"]',
68 | events: 'DOMMouseScroll mousewheel scroll touchstart touchmove'
69 | });
70 | ```
71 |
72 |
73 | ### Advanced use
74 |
75 | If you need full access to `ScrollScope` object (for example to `getTargetedElements()` or `unbind()` it later), instantiate a raw `ScrollScope` object yourself. You need to bind it to the document yourself in this case:
76 |
77 | ```js
78 | // Create new instance
79 | var myScrollScopeInstance = new ScrollScope({
80 | options: 'here'
81 | });
82 |
83 | // Bind to document
84 | myScrollScopeInstance.bind(document);
85 |
86 | // Use the object for whatever you wish
87 | myScrollScopeInstance.mainContainer.css('background', 'blue');
88 | myScrollScopeInstance.getTargetedElements().css('background', 'red');
89 |
90 | // Detach from document if no longer needed
91 | myScrollScope.unbind();
92 | ```
93 |
94 |
95 |
96 | ## Credits
97 |
98 | Plugin by [Jerry Jäppinen](http://eiskis.net/) (under [MIT](https://github.com/Eiskis/scroll-scope/blob/master/LICENSE)).
99 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scroll-scope",
3 | "main": "scroll-scope.js",
4 | "version": "0.1.0",
5 | "homepage": "http://eiskis.net/scroll-scope",
6 | "authors": [
7 | "Jerry Jäppinen Small jQuery plugin to keep parent element still when scrolling an element to its boundary.
63 |Commonly in scroll interaction, user hovers a mouse cursor over a scrollable element and uses trackpad or mouse wheel to scroll the element. When an element reaches its boundary, its parent element continues scrolling. Usually this means that the user will continue moving down the page when attempting to interact with an specific container. This is a common issue with dropdown menus and modal dialogs.
64 |This behavior is most prevalent in desktop browsers. To fix this problem that shouldn't even exist, scroll-scope.js exists.
65 |See project home and demos on scroll-scope.vercel.app.
66 |Current version is 0.1.0.
68 |Install with Bower:
73 |bower install scroll-scope
74 | File issues or pull requests to share potential improvements. The plugin is released under MIT. Source is available on GitHub. To contribute, clone the repo, make changes in scroll-scope.js and build the minified version with gulp
.
Add the data-scroll-scope
attribute to any scrollable element on the page:
<!-- Scope scrolling of element when it overflows -->
78 | <div class="my-scrollable-element" data-scroll-scope>
79 |
80 | <!-- Scope scrolling of element whether or not it overflows -->
81 | <div class="another-scrollable-element" data-scroll-scope="force">
82 | Include and initialize:
83 |<!-- jQuery comes first, then the plugin -->
84 | <script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.min.js"></script>
85 | <script type="text/javascript" src="scroll-scope.min.js"></script>
86 |
87 | <!-- Activate the plugin on your page -->
88 | <script type="text/javascript">
89 | $(document).scrollScope();
90 | </script>
91 | The plugin works declaratively, meaning that it's attached to the document object (or any parent container you choose) instead of individual scrollable containers. This means that any DOM elements that are added or removed after page load do not need to be bound separately. You can even toggle force
on and off during runtime if you please.
You can change which elements and events are targeted by setting them upon initialization. Note that having events listed here does not mean they're blocked automatically, rather the plugin listens to these events and evaluates them when encountered.
94 |Here are the defaults:
95 |$(document).scrollScope({
96 | elements: '[data-scroll-scope]',
97 | forcedElements: '[data-scroll-scope="force"]',
98 | events: 'DOMMouseScroll mousewheel scroll touchstart touchmove'
99 | });
100 | If you need full access to ScrollScope
object (for example to getTargetedElements()
or unbind()
it later), instantiate a raw ScrollScope
object yourself. You need to bind it to the document yourself in this case:
// Create new instance
103 | var myScrollScopeInstance = new ScrollScope({
104 | options: 'here'
105 | });
106 |
107 | // Bind to document
108 | myScrollScopeInstance.bind(document);
109 |
110 | // Use the object for whatever you wish
111 | myScrollScopeInstance.mainContainer.css('background', 'blue');
112 | myScrollScopeInstance.getTargetedElements().css('background', 'red');
113 |
114 | // Detach from document if no longer needed
115 | myScrollScope.unbind();
116 | Plugin by Jerry Jäppinen (under MIT).
118 |Default behavior
130 |data-scroll-scope
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
140 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
141 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
142 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
150 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
151 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
152 |When scrolling the container on the right, scrolling should stop when you get to the end and your document should stay still. For some browsers, this is also the default behavior.
159 | 160 |Also keep in mind that especially mobile browsers allow the user to keep scrolling the parent if the child is at its respective boundary when initiating the scroll. If you want to block scrolling even in these cases, use force
(see modal dialog example below).
The document will stay still even when you scroll the results container to the end.
167 | 168 | 193 | 194 | 195 | 196 |/*A page with lots of code blocks could set a max-height for them*/
201 | pre {
202 | overflow: auto;
203 | max-height: 16em;
204 | }
205 |
206 | /*Lots of code*/
207 | code {
208 | display: inline-block;
209 | color: #555;
210 | background-color: #f6f6f6;
211 | border-radius: 3px;
212 | padding-left: 0.3em;
213 | padding-right: 0.3em;
214 | }
215 | pre code {
216 | display: block;
217 | padding: 1em;
218 | overflow: auto;
219 | }
220 |
221 |
222 |
223 | Modal dialog implementations tend to scroll the document. Even Bootstrap's modal dialog overlay lets the scroll event through on mobile Safari!
253 | 254 | 255 | 256 |In this quite trivial custom dialog implementation, we scope the scrolling in both the overall container and the content area so the document maintains its position. We also want to use force
to disable parent scrolling even when the areas do not overflow.
Note! When scroll events are blocked with force
, mobile Safari also blocks click events for that element. To close the modal on overlay click, we must attach the click event handler to an element that does not use data-scroll-scope
.
The source looks like this:
261 | 262 |<div class="modal" data-scroll-scope="force">
263 | <div class="modal-content" data-scroll-scope="force">
264 | ...
265 | </div>
266 | <div class="modal-overlay" data-action="toggle-modal"></div>
267 | </div>
268 |
269 | // Quick custom toggle
270 | $(document).on('click', '[data-action="toggle-modal"]', function (event) {
271 | event.preventDefault();
272 | $('.modal').toggleClass('closed');
273 | });
274 |
275 | .modal {
276 | position: fixed;
277 | z-index: 100;
278 | width: 100%;
279 | height: 100%;
280 | left: 0;
281 | top: 0;
282 | overflow: hidden;
283 | }
284 | .modal.closed {
285 | display: none;
286 | }
287 | .modal-overlay {
288 | position: fixed;
289 | z-index: 1;
290 | width: 100%;
291 | height: 100%;
292 | top: 0;
293 | left: 0;
294 | background-color: rgba(0, 0, 0, 0.5);
295 | }
296 | .modal-content {
297 | position: fixed;
298 | z-index: 2;
299 | overflow: auto;
300 | top: 5%;
301 | left: 5%;
302 | width: 90%;
303 | height: 30em;
304 | max-height: 90%;
305 | background-color: #fff;
306 | }
307 |
308 |
309 |
310 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
316 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
317 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
318 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
332 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
333 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
334 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
335 |') 1445 | { 1446 | $markup = $trimmedMarkup; 1447 | $markup = substr($markup, 3); 1448 | 1449 | $position = strpos($markup, "
"); 1450 | 1451 | $markup = substr_replace($markup, '', $position, 4); 1452 | } 1453 | 1454 | return $markup; 1455 | } 1456 | 1457 | # 1458 | # Deprecated Methods 1459 | # 1460 | 1461 | function parse($text) 1462 | { 1463 | $markup = $this->text($text); 1464 | 1465 | return $markup; 1466 | } 1467 | 1468 | # 1469 | # Static Methods 1470 | # 1471 | 1472 | static function instance($name = 'default') 1473 | { 1474 | if (isset(self::$instances[$name])) 1475 | { 1476 | return self::$instances[$name]; 1477 | } 1478 | 1479 | $instance = new self(); 1480 | 1481 | self::$instances[$name] = $instance; 1482 | 1483 | return $instance; 1484 | } 1485 | 1486 | private static $instances = array(); 1487 | 1488 | # 1489 | # Fields 1490 | # 1491 | 1492 | protected $DefinitionData; 1493 | 1494 | # 1495 | # Read-Only 1496 | 1497 | protected $specialCharacters = array( 1498 | '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', 1499 | ); 1500 | 1501 | protected $StrongRegex = array( 1502 | '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', 1503 | '_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', 1504 | ); 1505 | 1506 | protected $EmRegex = array( 1507 | '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', 1508 | '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', 1509 | ); 1510 | 1511 | protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; 1512 | 1513 | protected $voidElements = array( 1514 | 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 1515 | ); 1516 | 1517 | protected $textLevelElements = array( 1518 | 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', 1519 | 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', 1520 | 'i', 'rp', 'del', 'code', 'strike', 'marquee', 1521 | 'q', 'rt', 'ins', 'font', 'strong', 1522 | 's', 'tt', 'sub', 'mark', 1523 | 'u', 'xm', 'sup', 'nobr', 1524 | 'var', 'ruby', 1525 | 'wbr', 'span', 1526 | 'time', 1527 | ); 1528 | } 1529 | -------------------------------------------------------------------------------- /php/index.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 |Default behavior
82 |data-scroll-scope
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
92 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
93 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
94 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
102 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
103 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis.
104 |When scrolling the container on the right, scrolling should stop when you get to the end and your document should stay still. For some browsers, this is also the default behavior.
111 | 112 |Also keep in mind that especially mobile browsers allow the user to keep scrolling the parent if the child is at its respective boundary when initiating the scroll. If you want to block scrolling even in these cases, use force
(see modal dialog example below).
The document will stay still even when you scroll the results container to the end.
119 | 120 | 145 | 146 | 147 | 148 |/*A page with lots of code blocks could set a max-height for them*/
153 | pre {
154 | overflow: auto;
155 | max-height: 16em;
156 | }
157 |
158 | /*Lots of code*/
159 | code {
160 | display: inline-block;
161 | color: #555;
162 | background-color: #f6f6f6;
163 | border-radius: 3px;
164 | padding-left: 0.3em;
165 | padding-right: 0.3em;
166 | }
167 | pre code {
168 | display: block;
169 | padding: 1em;
170 | overflow: auto;
171 | }
172 |
173 |
174 |
175 | Modal dialog implementations tend to scroll the document. Even Bootstrap's modal dialog overlay lets the scroll event through on mobile Safari!
205 | 206 | 207 | 208 |In this quite trivial custom dialog implementation, we scope the scrolling in both the overall container and the content area so the document maintains its position. We also want to use force
to disable parent scrolling even when the areas do not overflow.
Note! When scroll events are blocked with force
, mobile Safari also blocks click events for that element. To close the modal on overlay click, we must attach the click event handler to an element that does not use data-scroll-scope
.
The source looks like this:
213 | 214 |<div class="modal" data-scroll-scope="force">
215 | <div class="modal-content" data-scroll-scope="force">
216 | ...
217 | </div>
218 | <div class="modal-overlay" data-action="toggle-modal"></div>
219 | </div>
220 |
221 | // Quick custom toggle
222 | $(document).on('click', '[data-action="toggle-modal"]', function (event) {
223 | event.preventDefault();
224 | $('.modal').toggleClass('closed');
225 | });
226 |
227 | .modal {
228 | position: fixed;
229 | z-index: 100;
230 | width: 100%;
231 | height: 100%;
232 | left: 0;
233 | top: 0;
234 | overflow: hidden;
235 | }
236 | .modal.closed {
237 | display: none;
238 | }
239 | .modal-overlay {
240 | position: fixed;
241 | z-index: 1;
242 | width: 100%;
243 | height: 100%;
244 | top: 0;
245 | left: 0;
246 | background-color: rgba(0, 0, 0, 0.5);
247 | }
248 | .modal-content {
249 | position: fixed;
250 | z-index: 2;
251 | overflow: auto;
252 | top: 5%;
253 | left: 5%;
254 | width: 90%;
255 | height: 30em;
256 | max-height: 90%;
257 | background-color: #fff;
258 | }
259 |
260 |
261 |
262 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
268 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
269 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
270 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
284 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
285 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
286 |Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia aliquam, nemo molestiae consequatur officiis magni eos aliquid incidunt perspiciatis. Laudantium dolorum reprehenderit corporis dignissimos eaque, possimus quam, sequi ab soluta.
287 |