├── .gitignore ├── LICENSE ├── README.md ├── css ├── app.css └── layer-tree.css ├── dist ├── css │ └── styles.min.css └── js │ └── scripts.min.js ├── gulpfile.js ├── icons └── airplane.svg ├── index.html ├── js ├── app.js ├── jquery-ui-sortable │ ├── AUTHORS.txt │ ├── LICENSE.txt │ ├── external │ │ └── jquery │ │ │ └── jquery.js │ ├── index.html │ ├── jquery-ui.css │ ├── jquery-ui.js │ ├── jquery-ui.min.css │ ├── jquery-ui.min.js │ ├── jquery-ui.structure.css │ ├── jquery-ui.structure.min.css │ └── package.json ├── layer-tree.js └── onClickLoad-example.js ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 The Gartrell Group 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mapbox GL JS Layer Tree for the PORT 2 | #### Allow users to interactively organize and reposition different map layers. 3 | 4 | #### [Demo](http://dev.gartrellgroup.com/layer-tree/) 5 | 6 | ### Install: 7 | - `yarn` to install current set of dependencies 8 | - Additional dependencies can be installed via `yarn add [packagename]` 9 | - `gulp` to develop locally (includes a local server and watchers on index.html, js, and css files) 10 | - `gulp build` will compile/minify required javascript and default layer-tree.css. 11 | 12 | 13 | ### Dependencies: 14 | - jQuery, jQuery UI Sortable Module, and Font-Awesome are all currently required. 15 | - jQuery and jQuery UI-Sortable are both included within the compiled `dist/js/scripts.min.js` 16 | - Font-Awesome CSS should be added in your HTML `` 17 | 18 | ### Regular Usage: 19 | - #### Layer Config: 20 | - **name** - to be displayed as the layer name in Legend 21 | - **id** - layer id 22 | - **source** - layer source 23 | - **directory** - directory where the layer is apart of 24 | - **icon** (optional) - path to img src and is solely reflected in the Layer Tree legend. It does not modify the symbology of a layer. Additionally, in a group layer object configuration - the icon param can inherit a child layer's default icon style - via the child layer's ID. 25 | - **path** (optional) - references source path for geojson and is *only* used in conjunction with onClickLoad param (see further below) 26 | - **hideLabel** (optional - group layer only) - in a group layer object configuration, this can be used to hide specific child layers from the Layer Tree by using an array of child layer IDs. 27 | 28 | ```javascript 29 | var lyrArray = 30 | [ 31 | { 32 | 'name': 'Geographic Regions', 33 | 'id': 'geo-regions', 34 | 'source': 'geo-regions', 35 | 'directory': 'Misc', 36 | }, 37 | { 38 | 'name': 'Land', 39 | 'id': 'land', 40 | 'source': 'land', 41 | 'directory': 'Natural', 42 | }, 43 | { 44 | 'name': 'Glaciers', 45 | 'id': 'glaciers', 46 | 'source': 'glacial', 47 | 'directory': 'Natural', 48 | 'icon': 'http://external.image.png' 49 | }, 50 | { 51 | 'name': 'Boundary Lines', 52 | 'id': 'boundary-line', 53 | 'source': 'boundary', 54 | 'directory': 'Travel', 55 | }, 56 | { 57 | 'name': 'Points', 58 | 'id': 'travel-group', 59 | 'icon': 'port', 60 | 'hideLabel': ['port', 'airport'], 61 | 'layerGroup' : [ 62 | { 63 | 'id': 'port', 64 | 'source': 'ports', 65 | 'name': 'Major Shipping Ports' 66 | }, 67 | { 68 | 'id': 'airport', 69 | 'source': 'airports', 70 | 'name': 'Airports' 71 | }, 72 | ], 73 | 'directory': 'Travel' 74 | } 75 | ]; 76 | ``` 77 | ##### onClickLoad (optional) 78 | Since the Layer Tree is populated within `map.on('load', function()`, *mapLayers* and *mapSources* are added inside the event listener. Often times, may want to load layers only on 'click'. To account for this (*geojson only*), users will need to initially setup their layers sources with empty featureCollections. The `onClickLoad` param also needs to be added to LayerTree control and must be set to `true`. If a geojson layer has a layout visibility not set to 'none' - the Layer Tree will behave as it normally would - where the layer will be activated and shown on map load. 79 | 80 | Example js setup [here](https://github.com/TheGartrellGroup/Mapbox-GL-JS-Layer-Tree/blob/master/js/onClickLoad-example.js) 81 | 82 | ```javascript 83 | // **** EMPTY GEOJSON PLACEHOLDER **** 84 | var emptyGJ = { 85 | 'type': 'FeatureCollection', 86 | 'features': [] 87 | }; 88 | 89 | map.on('load', function () { 90 | // *** emptyGJ is now the initial data source *** 91 | map.addSource('land', { type: 'geojson', data: emptyGJ }); 92 | map.addLayer({ 93 | "id": "land", 94 | "type": "fill", 95 | "source": "land", 96 | "paint": { 97 | 'fill-color': '#a89b97', 98 | 'fill-opacity': 0.8 99 | } 100 | }); 101 | 102 | var layers = 103 | [ 104 | { 105 | 'name': 'Land', 106 | 'id': 'land', 107 | 'source': 'land', 108 | // **** SOURCE PATH IS NOW HERE **** 109 | 'path': 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_land.geojson', 110 | 'directory': 'Directory 1', 111 | } 112 | ]; 113 | ``` 114 | - #### Layer Directory - Open/Closed (Optional) 115 | - A directory can be set to open or close on load (they'll default to open if no overriding configuration is passed) 116 | ```javascript 117 | var directoryOptions = 118 | [ 119 | { 120 | 'name': 'Natural', 121 | 'open': false 122 | } 123 | ] 124 | ``` 125 | 126 | - #### Instantiate Layer Tree 127 | ```javascript 128 | map.addControl(new LayerTree({ 129 | layers: lyrArray, 130 | directoryOptions: directoryOptions, 131 | }, 'bottom-left') 132 | ``` 133 | 134 | ### Notes: 135 | - Layers within the same directory **must** be configured together 136 | - For example: *Layer A* and *Layer C* can not be of the same directory - if *Layer B* is also **not** within the same directory and has been added as a mapLayer prior to *Layer C* being added. 137 | - If the layer is a geojson and no icon is passed to the layer config, the Layer Tree will automatically add a FontAwesome icon to the legend 138 | - Icon params within the layer config **only** update the legend - not layer symbology on the map 139 | - `onClickLoad` only works with geojson layers and should have layout visibilities set to 'none' 140 | -------------------------------------------------------------------------------- /css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin:0; padding:0; 3 | } 4 | 5 | #map { 6 | position:absolute; 7 | top:0; 8 | bottom:0; 9 | width:100%; 10 | } 11 | 12 | .toggle-directory-open, .toggle-directory-close { 13 | padding-top: 2px; 14 | } 15 | 16 | #airports img{ 17 | height: 15px; 18 | width: 15px; 19 | -webkit-text-stroke: 1px #FFF; 20 | } -------------------------------------------------------------------------------- /css/layer-tree.css: -------------------------------------------------------------------------------- 1 | /* jquery ui required */ 2 | .ui-sortable-handle{ 3 | -ms-touch-action: none; 4 | touch-action: none; 5 | } 6 | 7 | .mapboxgl-ctrl.legend-container { 8 | display: none; 9 | width: auto; 10 | height: auto; 11 | pointer-events: auto; 12 | margin: 0; 13 | float: none; 14 | } 15 | 16 | #mapboxgl-legend { 17 | padding: 5px; 18 | } 19 | 20 | .layer-directory .directory-name { 21 | font-size: 18px; 22 | font-weight: 500; 23 | padding: 5px; 24 | } 25 | 26 | .layer-directory .layer-item { 27 | font-size: 15px; 28 | font-weight: 400; 29 | padding: 2px 6px 2px 15px; 30 | } 31 | 32 | .layer-item input { 33 | margin-right: 5px; 34 | } 35 | 36 | .layer-item.ghost { 37 | color: #D3D3D3; 38 | } 39 | 40 | .layer-item span.name { 41 | margin-left: 5px; 42 | } 43 | 44 | .layer-item > img, .child-layer > img { 45 | height: 15px; 46 | width: 15px; 47 | } 48 | 49 | .child-layer { 50 | padding-left: 30px; 51 | font-size: 13px; 52 | } 53 | 54 | .child-layer span.child-name { 55 | padding-left: 5px; 56 | } 57 | /* .grb is class for all sortable components */ 58 | .grb { 59 | cursor: move; /* fallback if grab cursor is unsupported */ 60 | cursor: grab; 61 | cursor: -moz-grab; 62 | cursor: -webkit-grab; 63 | } 64 | 65 | .grb:active { 66 | cursor: grabbing; 67 | cursor: -moz-grabbing; 68 | cursor: -webkit-grabbing; 69 | } 70 | 71 | /* font awesome classes */ 72 | .geojson-polygon:before { 73 | content: "\f0c8"; 74 | } 75 | 76 | .geojson-circle:before { 77 | content: "\f111"; 78 | } 79 | 80 | .geojson-line-solid:before { 81 | content: "\f068"; 82 | } 83 | 84 | .geojson-line-dashed:before { 85 | content: "\f141"; 86 | } 87 | 88 | .toggle-directory-open, .toggle-directory-close { 89 | float: left; 90 | margin-right: 5px; 91 | } 92 | .toggle-directory-open:before{ 93 | content: "\f07c"; 94 | } 95 | 96 | .toggle-directory-close:before { 97 | content: "\f07b"; 98 | } 99 | -------------------------------------------------------------------------------- /dist/css/styles.min.css: -------------------------------------------------------------------------------- 1 | .ui-sortable-handle{-ms-touch-action:none;touch-action:none}.mapboxgl-ctrl.legend-container{display:none;width:auto;height:auto;pointer-events:auto;margin:0;float:none}#mapboxgl-legend{padding:5px}.layer-directory .directory-name{font-size:18px;font-weight:500;padding:5px}.layer-directory .layer-item{font-size:15px;font-weight:400;padding:2px 6px 2px 15px}.layer-item input{margin-right:5px}.layer-item.ghost{color:#d3d3d3}.layer-item span.name{margin-left:5px}.child-layer>img,.layer-item>img{height:15px;width:15px}.child-layer{padding-left:30px;font-size:13px}.child-layer span.child-name{padding-left:5px}.grb{cursor:move;cursor:grab;cursor:-moz-grab;cursor:-webkit-grab}.grb:active{cursor:grabbing;cursor:-moz-grabbing;cursor:-webkit-grabbing}.geojson-polygon:before{content:"\f0c8"}.geojson-circle:before{content:"\f111"}.geojson-line-solid:before{content:"\f068"}.geojson-line-dashed:before{content:"\f141"}.toggle-directory-close,.toggle-directory-open{float:left;margin-right:5px}.toggle-directory-open:before{content:"\f07c"}.toggle-directory-close:before{content:"\f07b"} -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var webserver = require('gulp-webserver'); 3 | var concat = require('gulp-concat'); 4 | var uglify = require('gulp-uglify'); 5 | var cleanCSS = require('gulp-clean-css'); 6 | 7 | //local webserver 8 | gulp.task('webserver', function() { 9 | gulp.src('./') 10 | .pipe(webserver({ 11 | fallback: 'index.html', 12 | directoryListing: false, 13 | livereload: true, 14 | open: true 15 | })); 16 | }); 17 | 18 | //watch task 19 | gulp.task('watch', function(){ 20 | gulp.watch(['index.htm', 'js/app.js', 'js/layer-tree.js', 'css/app.css', 'css/layer-tree.css']); 21 | }); 22 | 23 | //minify js 24 | gulp.task('scripts', function() { 25 | gulp.src(['node_modules/jquery/dist/jquery.min.js', 'js/jquery-ui-sortable/jquery-ui.min.js', 'js/layer-tree.js']) 26 | .pipe(concat('scripts.min.js')) 27 | .pipe(uglify()) 28 | .pipe(gulp.dest('dist/js')) 29 | }); 30 | 31 | //minify css 32 | gulp.task('css', function() { 33 | gulp.src(['css/layer-tree.css']) 34 | .pipe(concat('styles.min.css')) 35 | .pipe(cleanCSS()) 36 | .pipe(gulp.dest('dist/css')) 37 | }); 38 | 39 | //default task 40 | gulp.task('default', ['webserver', 'watch']); 41 | 42 | //build task 43 | gulp.task('build', ['scripts', 'css']); 44 | -------------------------------------------------------------------------------- /icons/airplane.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /js/app.js: -------------------------------------------------------------------------------- 1 | mapboxgl.accessToken = ''; 2 | 3 | var map = new mapboxgl.Map({ 4 | container: 'map', 5 | style: 'mapbox://styles/mapbox/light-v9', 6 | center: [-75, 15], 7 | zoom: 2 8 | }); 9 | 10 | 11 | map.on('load', function() { 12 | 13 | map.addSource('geo-regions', { type: 'geojson', data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_geography_regions_polys.geojson' }); 14 | map.addLayer({ 15 | "id": "geo-regions", 16 | "type": "fill", 17 | "source": "geo-regions", 18 | "layout": { 19 | "visibility": 'visible' 20 | }, 21 | "paint": { 22 | 'fill-color': '#4842f4', 23 | 'fill-opacity': 0.3 24 | } 25 | }); 26 | 27 | map.addSource('land', { type: 'geojson', data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_land.geojson' }); 28 | map.addLayer({ 29 | "id": "land", 30 | "type": "fill", 31 | "source": "land", 32 | "layout": { 33 | "visibility": 'visible' 34 | }, 35 | "paint": { 36 | 'fill-color': '#e0d4b8', 37 | 'fill-opacity': 0.8 38 | } 39 | }); 40 | 41 | map.addSource('glacial', { type: 'geojson', data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_glaciated_areas.geojson' }); 42 | map.addLayer({ 43 | "id": "glaciers", 44 | "type": "fill", 45 | "source": "glacial", 46 | "layout": { 47 | "visibility": 'visible' 48 | }, 49 | "paint": { 50 | 'fill-color': '#b8dae0', 51 | 'fill-opacity': 1 52 | } 53 | }); 54 | 55 | map.addSource('reefs', { type: 'geojson', data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_reefs.geojson' }); 56 | map.addLayer({ 57 | "id": "reefs", 58 | "type": "line", 59 | "source": "reefs", 60 | "paint": { 61 | "line-color": "#f45353", 62 | "line-width": 2 63 | } 64 | }); 65 | 66 | map.addSource('rivers', { type: 'geojson', data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_rivers_lake_centerlines_scale_rank.geojson' }); 67 | map.addLayer({ 68 | "id": "rivers", 69 | "type": "line", 70 | "source": "rivers", 71 | "layout": { 72 | 'visibility': 'visible' 73 | }, 74 | "paint": { 75 | "line-color": "#4177f4", 76 | "line-width": 2, 77 | "line-dasharray": [4, 4], 78 | } 79 | }); 80 | 81 | map.addSource('boundary', { type: 'geojson', data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_boundary_lines_land.geojson' }); 82 | map.addLayer({ 83 | "id": "boundary-line", 84 | "type": "line", 85 | "source": "boundary", 86 | "paint": { 87 | "line-color": "#e07a14", 88 | "line-width": 3, 89 | "line-dasharray": [2, 2], 90 | } 91 | }); 92 | 93 | 94 | map.addSource('ports', { type: 'geojson', data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_ports.geojson' }); 95 | map.addLayer({ 96 | "id": "port", 97 | "type": "circle", 98 | "source": "ports", 99 | "paint": { 100 | 'circle-color': '#35a045', 101 | 'circle-opacity': 0.8, 102 | 'circle-stroke-color': '#000', 103 | 'circle-stroke-width': 1 104 | } 105 | }); 106 | 107 | map.setFilter('port', ['<', 'natlscale', 6]); 108 | 109 | map.addSource('airports', { type: 'geojson', data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson' }); 110 | map.addLayer({ 111 | "id": "airport", 112 | "type": "symbol", 113 | "source": "airports", 114 | "layout": { 115 | "icon-image": "airport-11" 116 | }, 117 | "paint": { 118 | "icon-color": '#0dd224', 119 | "icon-halo-color": "#0dd224" 120 | } 121 | }); 122 | }) 123 | 124 | 125 | var layers = 126 | 127 | [{ 128 | 'name': 'Geographic Regions', 129 | 'id': 'geo-regions', 130 | 'source': 'geo-regions', 131 | 'directory': 'Misc', 132 | }, { 133 | 'name': 'Land', 134 | 'id': 'land', 135 | 'source': 'land', 136 | 'directory': 'Natural', 137 | }, { 138 | 'name': 'Glaciers', 139 | 'id': 'glaciers', 140 | 'source': 'glacial', 141 | 'directory': 'Natural', 142 | }, { 143 | 'name': 'Reef Boundaries', 144 | 'id': 'reefs', 145 | 'source': 'reefs', 146 | 'directory': 'Natural', 147 | }, { 148 | 'name': 'Rivers', 149 | 'id': 'rivers', 150 | 'source': 'rivers', 151 | 'directory': 'Natural', 152 | }, { 153 | 'name': 'Boundary Lines', 154 | 'id': 'boundary-line', 155 | 'source': 'boundary', 156 | 'directory': 'Travel', 157 | }, { 158 | 'name': 'Points', 159 | 'id': 'travel-group', 160 | 'layerGroup': [{ 161 | 'id': 'port', 162 | 'source': 'ports', 163 | 'name': 'Major Shipping Ports' 164 | }, { 165 | 'id': 'airport', 166 | 'source': 'airports', 167 | 'name': 'Airports', 168 | 'icon': '../icons/airplane.svg' 169 | }, ], 170 | 'directory': 'Travel' 171 | }]; 172 | 173 | var directoryOptions = [{ 'name': 'Travel', 'open': false }] 174 | 175 | // Add zoom and rotation controls to the map. 176 | map.addControl(new mapboxgl.NavigationControl()); 177 | map.addControl(new LayerTree({ 178 | layers: layers, 179 | directoryOptions: directoryOptions 180 | }), 'bottom-left'); -------------------------------------------------------------------------------- /js/jquery-ui-sortable/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Authors ordered by first contribution 2 | A list of current team members is available at http://jqueryui.com/about 3 | 4 | Paul Bakaus 5 | Richard Worth 6 | Yehuda Katz 7 | Sean Catchpole 8 | John Resig 9 | Tane Piper 10 | Dmitri Gaskin 11 | Klaus Hartl 12 | Stefan Petre 13 | Gilles van den Hoven 14 | Micheil Bryan Smith 15 | Jörn Zaefferer 16 | Marc Grabanski 17 | Keith Wood 18 | Brandon Aaron 19 | Scott González 20 | Eduardo Lundgren 21 | Aaron Eisenberger 22 | Joan Piedra 23 | Bruno Basto 24 | Remy Sharp 25 | Bohdan Ganicky 26 | David Bolter 27 | Chi Cheng 28 | Ca-Phun Ung 29 | Ariel Flesler 30 | Maggie Wachs 31 | Scott Jehl 32 | Todd Parker 33 | Andrew Powell 34 | Brant Burnett 35 | Douglas Neiner 36 | Paul Irish 37 | Ralph Whitbeck 38 | Thibault Duplessis 39 | Dominique Vincent 40 | Jack Hsu 41 | Adam Sontag 42 | Carl Fürstenberg 43 | Kevin Dalman 44 | Alberto Fernández Capel 45 | Jacek Jędrzejewski (http://jacek.jedrzejewski.name) 46 | Ting Kuei 47 | Samuel Cormier-Iijima 48 | Jon Palmer 49 | Ben Hollis 50 | Justin MacCarthy 51 | Eyal Kobrigo 52 | Tiago Freire 53 | Diego Tres 54 | Holger Rüprich 55 | Ziling Zhao 56 | Mike Alsup 57 | Robson Braga Araujo 58 | Pierre-Henri Ausseil 59 | Christopher McCulloh 60 | Andrew Newcomb 61 | Lim Chee Aun 62 | Jorge Barreiro 63 | Daniel Steigerwald 64 | John Firebaugh 65 | John Enters 66 | Andrey Kapitcyn 67 | Dmitry Petrov 68 | Eric Hynds 69 | Chairat Sunthornwiphat 70 | Josh Varner 71 | Stéphane Raimbault 72 | Jay Merrifield 73 | J. Ryan Stinnett 74 | Peter Heiberg 75 | Alex Dovenmuehle 76 | Jamie Gegerson 77 | Raymond Schwartz 78 | Phillip Barnes 79 | Kyle Wilkinson 80 | Khaled AlHourani 81 | Marian Rudzynski 82 | Jean-Francois Remy 83 | Doug Blood 84 | Filippo Cavallarin 85 | Heiko Henning 86 | Aliaksandr Rahalevich 87 | Mario Visic 88 | Xavi Ramirez 89 | Max Schnur 90 | Saji Nediyanchath 91 | Corey Frang 92 | Aaron Peterson 93 | Ivan Peters 94 | Mohamed Cherif Bouchelaghem 95 | Marcos Sousa 96 | Michael DellaNoce 97 | George Marshall 98 | Tobias Brunner 99 | Martin Solli 100 | David Petersen 101 | Dan Heberden 102 | William Kevin Manire 103 | Gilmore Davidson 104 | Michael Wu 105 | Adam Parod 106 | Guillaume Gautreau 107 | Marcel Toele 108 | Dan Streetman 109 | Matt Hoskins 110 | Giovanni Giacobbi 111 | Kyle Florence 112 | Pavol Hluchý 113 | Hans Hillen 114 | Mark Johnson 115 | Trey Hunner 116 | Shane Whittet 117 | Edward A Faulkner 118 | Adam Baratz 119 | Kato Kazuyoshi 120 | Eike Send 121 | Kris Borchers 122 | Eddie Monge 123 | Israel Tsadok 124 | Carson McDonald 125 | Jason Davies 126 | Garrison Locke 127 | David Murdoch 128 | Benjamin Scott Boyle 129 | Jesse Baird 130 | Jonathan Vingiano 131 | Dylan Just 132 | Hiroshi Tomita 133 | Glenn Goodrich 134 | Tarafder Ashek-E-Elahi 135 | Ryan Neufeld 136 | Marc Neuwirth 137 | Philip Graham 138 | Benjamin Sterling 139 | Wesley Walser 140 | Kouhei Sutou 141 | Karl Kirch 142 | Chris Kelly 143 | Jason Oster 144 | Felix Nagel 145 | Alexander Polomoshnov 146 | David Leal 147 | Igor Milla 148 | Dave Methvin 149 | Florian Gutmann 150 | Marwan Al Jubeh 151 | Milan Broum 152 | Sebastian Sauer 153 | Gaëtan Muller 154 | Michel Weimerskirch 155 | William Griffiths 156 | Stojce Slavkovski 157 | David Soms 158 | David De Sloovere 159 | Michael P. Jung 160 | Shannon Pekary 161 | Dan Wellman 162 | Matthew Edward Hutton 163 | James Khoury 164 | Rob Loach 165 | Alberto Monteiro 166 | Alex Rhea 167 | Krzysztof Rosiński 168 | Ryan Olton 169 | Genie <386@mail.com> 170 | Rick Waldron 171 | Ian Simpson 172 | Lev Kitsis 173 | TJ VanToll 174 | Justin Domnitz 175 | Douglas Cerna 176 | Bert ter Heide 177 | Jasvir Nagra 178 | Yuriy Khabarov <13real008@gmail.com> 179 | Harri Kilpiö 180 | Lado Lomidze 181 | Amir E. Aharoni 182 | Simon Sattes 183 | Jo Liss 184 | Guntupalli Karunakar 185 | Shahyar Ghobadpour 186 | Lukasz Lipinski 187 | Timo Tijhof 188 | Jason Moon 189 | Martin Frost 190 | Eneko Illarramendi 191 | EungJun Yi 192 | Courtland Allen 193 | Viktar Varvanovich 194 | Danny Trunk 195 | Pavel Stetina 196 | Michael Stay 197 | Steven Roussey 198 | Michael Hollis 199 | Lee Rowlands 200 | Timmy Willison 201 | Karl Swedberg 202 | Baoju Yuan 203 | Maciej Mroziński 204 | Luis Dalmolin 205 | Mark Aaron Shirley 206 | Martin Hoch 207 | Jiayi Yang 208 | Philipp Benjamin Köppchen 209 | Sindre Sorhus 210 | Bernhard Sirlinger 211 | Jared A. Scheel 212 | Rafael Xavier de Souza 213 | John Chen 214 | Robert Beuligmann 215 | Dale Kocian 216 | Mike Sherov 217 | Andrew Couch 218 | Marc-Andre Lafortune 219 | Nate Eagle 220 | David Souther 221 | Mathias Stenbom 222 | Sergey Kartashov 223 | Avinash R 224 | Ethan Romba 225 | Cory Gackenheimer 226 | Juan Pablo Kaniefsky 227 | Roman Salnikov 228 | Anika Henke 229 | Samuel Bovée 230 | Fabrício Matté 231 | Viktor Kojouharov 232 | Pawel Maruszczyk (http://hrabstwo.net) 233 | Pavel Selitskas 234 | Bjørn Johansen 235 | Matthieu Penant 236 | Dominic Barnes 237 | David Sullivan 238 | Thomas Jaggi 239 | Vahid Sohrabloo 240 | Travis Carden 241 | Bruno M. Custódio 242 | Nathanael Silverman 243 | Christian Wenz 244 | Steve Urmston 245 | Zaven Muradyan 246 | Woody Gilk 247 | Zbigniew Motyka 248 | Suhail Alkowaileet 249 | Toshi MARUYAMA 250 | David Hansen 251 | Brian Grinstead 252 | Christian Klammer 253 | Steven Luscher 254 | Gan Eng Chin 255 | Gabriel Schulhof 256 | Alexander Schmitz 257 | Vilhjálmur Skúlason 258 | Siebrand Mazeland 259 | Mohsen Ekhtiari 260 | Pere Orga 261 | Jasper de Groot 262 | Stephane Deschamps 263 | Jyoti Deka 264 | Andrei Picus 265 | Ondrej Novy 266 | Jacob McCutcheon 267 | Monika Piotrowicz 268 | Imants Horsts 269 | Eric Dahl 270 | Dave Stein 271 | Dylan Barrell 272 | Daniel DeGroff 273 | Michael Wiencek 274 | Thomas Meyer 275 | Ruslan Yakhyaev 276 | Brian J. Dowling 277 | Ben Higgins 278 | Yermo Lamers 279 | Patrick Stapleton 280 | Trisha Crowley 281 | Usman Akeju 282 | Rodrigo Menezes 283 | Jacques Perrault 284 | Frederik Elvhage 285 | Will Holley 286 | Uri Gilad 287 | Richard Gibson 288 | Simen Bekkhus 289 | Chen Eshchar 290 | Bruno Pérel 291 | Mohammed Alshehri 292 | Lisa Seacat DeLuca 293 | Anne-Gaelle Colom 294 | Adam Foster 295 | Luke Page 296 | Daniel Owens 297 | Michael Orchard 298 | Marcus Warren 299 | Nils Heuermann 300 | Marco Ziech 301 | Patricia Juarez 302 | Ben Mosher 303 | Ablay Keldibek 304 | Thomas Applencourt 305 | Jiabao Wu 306 | Eric Lee Carraway 307 | Victor Homyakov 308 | Myeongjin Lee 309 | Liran Sharir 310 | Weston Ruter 311 | Mani Mishra 312 | Hannah Methvin 313 | Leonardo Balter 314 | Benjamin Albert 315 | Michał Gołębiowski 316 | Alyosha Pushak 317 | Fahad Ahmad 318 | Matt Brundage 319 | Francesc Baeta 320 | Piotr Baran 321 | Mukul Hase 322 | Konstantin Dinev 323 | Rand Scullard 324 | Dan Strohl 325 | Maksim Ryzhikov 326 | Amine HADDAD 327 | Amanpreet Singh 328 | Alexey Balchunas 329 | Peter Kehl 330 | Peter Dave Hello 331 | Johannes Schäfer 332 | Ville Skyttä 333 | Ryan Oriecuia 334 | -------------------------------------------------------------------------------- /js/jquery-ui-sortable/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery-ui 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | Copyright and related rights for sample code are waived via CC0. Sample 34 | code is defined as all source code contained within the demos directory. 35 | 36 | CC0: http://creativecommons.org/publicdomain/zero/1.0/ 37 | 38 | ==== 39 | 40 | All files located in the node_modules and external directories are 41 | externally maintained libraries used by this software which have their 42 | own licenses; we recommend you read them, as their terms may differ from 43 | the terms above. 44 | -------------------------------------------------------------------------------- /js/jquery-ui-sortable/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery UI Example Page 6 | 7 | 50 | 51 | 52 | 53 |

Welcome to jQuery UI!

54 | 55 |
56 |

This page demonstrates the widgets and theme you selected in Download Builder. Please make sure you are using them with a compatible jQuery version.

57 |
58 | 59 |

YOUR COMPONENTS:

60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |

Framework Icons (content color preview)

77 |
    78 |
  • 79 |
  • 80 |
  • 81 |
  • 82 |
  • 83 |
  • 84 |
  • 85 |
  • 86 |
  • 87 |
  • 88 |
  • 89 |
  • 90 |
  • 91 |
  • 92 |
  • 93 |
  • 94 |
  • 95 |
  • 96 |
  • 97 |
  • 98 |
  • 99 |
  • 100 |
  • 101 |
  • 102 |
  • 103 |
  • 104 |
  • 105 |
  • 106 |
  • 107 |
  • 108 |
  • 109 |
  • 110 |
  • 111 |
  • 112 |
  • 113 |
  • 114 |
  • 115 |
  • 116 |
  • 117 |
  • 118 |
  • 119 |
  • 120 |
  • 121 |
  • 122 |
  • 123 |
  • 124 |
  • 125 |
  • 126 |
  • 127 |
  • 128 |
  • 129 |
  • 130 |
  • 131 |
  • 132 |
  • 133 |
  • 134 |
  • 135 |
  • 136 |
  • 137 |
  • 138 |
  • 139 |
  • 140 |
  • 141 |
  • 142 |
  • 143 |
  • 144 |
  • 145 |
  • 146 |
  • 147 |
  • 148 |
  • 149 |
  • 150 |
  • 151 |
  • 152 |
  • 153 |
  • 154 |
  • 155 |
  • 156 |
  • 157 |
  • 158 |
  • 159 |
  • 160 |
  • 161 |
  • 162 |
  • 163 |
  • 164 |
  • 165 |
  • 166 |
  • 167 |
  • 168 |
  • 169 |
  • 170 |
  • 171 |
  • 172 |
  • 173 |
  • 174 |
  • 175 |
  • 176 |
  • 177 |
  • 178 |
  • 179 |
  • 180 |
  • 181 |
  • 182 |
  • 183 |
  • 184 |
  • 185 |
  • 186 |
  • 187 |
  • 188 |
  • 189 |
  • 190 |
  • 191 |
  • 192 |
  • 193 |
  • 194 |
  • 195 |
  • 196 |
  • 197 |
  • 198 |
  • 199 |
  • 200 |
  • 201 |
  • 202 |
  • 203 |
  • 204 |
  • 205 |
  • 206 |
  • 207 |
  • 208 |
  • 209 |
  • 210 |
  • 211 |
  • 212 |
  • 213 |
  • 214 |
  • 215 |
  • 216 |
  • 217 |
  • 218 |
  • 219 |
  • 220 |
  • 221 |
  • 222 |
  • 223 |
  • 224 |
  • 225 |
  • 226 |
  • 227 |
  • 228 |
  • 229 |
  • 230 |
  • 231 |
  • 232 |
  • 233 |
  • 234 |
  • 235 |
  • 236 |
  • 237 |
  • 238 |
  • 239 |
  • 240 |
  • 241 |
  • 242 |
  • 243 |
  • 244 |
  • 245 |
  • 246 |
  • 247 |
  • 248 |
  • 249 |
  • 250 |
  • 251 |
252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 |

Highlight / Error

269 |
270 |
271 |

272 | Hey! Sample ui-state-highlight style.

273 |
274 |
275 |
276 |
277 |
278 |

279 | Alert: Sample ui-state-error style.

280 |
281 |
282 | 283 | 284 | 285 | 324 | 325 | 326 | -------------------------------------------------------------------------------- /js/jquery-ui-sortable/jquery-ui.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2017-02-03 2 | * http://jqueryui.com 3 | * Includes: sortable.css 4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 5 | 6 | .ui-sortable-handle { 7 | -ms-touch-action: none; 8 | touch-action: none; 9 | } 10 | -------------------------------------------------------------------------------- /js/jquery-ui-sortable/jquery-ui.js: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2017-02-03 2 | * http://jqueryui.com 3 | * Includes: widget.js, data.js, scroll-parent.js, widgets/sortable.js, widgets/mouse.js 4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 5 | 6 | (function( factory ) { 7 | if ( typeof define === "function" && define.amd ) { 8 | 9 | // AMD. Register as an anonymous module. 10 | define([ "jquery" ], factory ); 11 | } else { 12 | 13 | // Browser globals 14 | factory( jQuery ); 15 | } 16 | }(function( $ ) { 17 | 18 | $.ui = $.ui || {}; 19 | 20 | var version = $.ui.version = "1.12.1"; 21 | 22 | 23 | /*! 24 | * jQuery UI Widget 1.12.1 25 | * http://jqueryui.com 26 | * 27 | * Copyright jQuery Foundation and other contributors 28 | * Released under the MIT license. 29 | * http://jquery.org/license 30 | */ 31 | 32 | //>>label: Widget 33 | //>>group: Core 34 | //>>description: Provides a factory for creating stateful widgets with a common API. 35 | //>>docs: http://api.jqueryui.com/jQuery.widget/ 36 | //>>demos: http://jqueryui.com/widget/ 37 | 38 | 39 | 40 | var widgetUuid = 0; 41 | var widgetSlice = Array.prototype.slice; 42 | 43 | $.cleanData = ( function( orig ) { 44 | return function( elems ) { 45 | var events, elem, i; 46 | for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { 47 | try { 48 | 49 | // Only trigger remove when necessary to save time 50 | events = $._data( elem, "events" ); 51 | if ( events && events.remove ) { 52 | $( elem ).triggerHandler( "remove" ); 53 | } 54 | 55 | // Http://bugs.jquery.com/ticket/8235 56 | } catch ( e ) {} 57 | } 58 | orig( elems ); 59 | }; 60 | } )( $.cleanData ); 61 | 62 | $.widget = function( name, base, prototype ) { 63 | var existingConstructor, constructor, basePrototype; 64 | 65 | // ProxiedPrototype allows the provided prototype to remain unmodified 66 | // so that it can be used as a mixin for multiple widgets (#8876) 67 | var proxiedPrototype = {}; 68 | 69 | var namespace = name.split( "." )[ 0 ]; 70 | name = name.split( "." )[ 1 ]; 71 | var fullName = namespace + "-" + name; 72 | 73 | if ( !prototype ) { 74 | prototype = base; 75 | base = $.Widget; 76 | } 77 | 78 | if ( $.isArray( prototype ) ) { 79 | prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); 80 | } 81 | 82 | // Create selector for plugin 83 | $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 84 | return !!$.data( elem, fullName ); 85 | }; 86 | 87 | $[ namespace ] = $[ namespace ] || {}; 88 | existingConstructor = $[ namespace ][ name ]; 89 | constructor = $[ namespace ][ name ] = function( options, element ) { 90 | 91 | // Allow instantiation without "new" keyword 92 | if ( !this._createWidget ) { 93 | return new constructor( options, element ); 94 | } 95 | 96 | // Allow instantiation without initializing for simple inheritance 97 | // must use "new" keyword (the code above always passes args) 98 | if ( arguments.length ) { 99 | this._createWidget( options, element ); 100 | } 101 | }; 102 | 103 | // Extend with the existing constructor to carry over any static properties 104 | $.extend( constructor, existingConstructor, { 105 | version: prototype.version, 106 | 107 | // Copy the object used to create the prototype in case we need to 108 | // redefine the widget later 109 | _proto: $.extend( {}, prototype ), 110 | 111 | // Track widgets that inherit from this widget in case this widget is 112 | // redefined after a widget inherits from it 113 | _childConstructors: [] 114 | } ); 115 | 116 | basePrototype = new base(); 117 | 118 | // We need to make the options hash a property directly on the new instance 119 | // otherwise we'll modify the options hash on the prototype that we're 120 | // inheriting from 121 | basePrototype.options = $.widget.extend( {}, basePrototype.options ); 122 | $.each( prototype, function( prop, value ) { 123 | if ( !$.isFunction( value ) ) { 124 | proxiedPrototype[ prop ] = value; 125 | return; 126 | } 127 | proxiedPrototype[ prop ] = ( function() { 128 | function _super() { 129 | return base.prototype[ prop ].apply( this, arguments ); 130 | } 131 | 132 | function _superApply( args ) { 133 | return base.prototype[ prop ].apply( this, args ); 134 | } 135 | 136 | return function() { 137 | var __super = this._super; 138 | var __superApply = this._superApply; 139 | var returnValue; 140 | 141 | this._super = _super; 142 | this._superApply = _superApply; 143 | 144 | returnValue = value.apply( this, arguments ); 145 | 146 | this._super = __super; 147 | this._superApply = __superApply; 148 | 149 | return returnValue; 150 | }; 151 | } )(); 152 | } ); 153 | constructor.prototype = $.widget.extend( basePrototype, { 154 | 155 | // TODO: remove support for widgetEventPrefix 156 | // always use the name + a colon as the prefix, e.g., draggable:start 157 | // don't prefix for widgets that aren't DOM-based 158 | widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name 159 | }, proxiedPrototype, { 160 | constructor: constructor, 161 | namespace: namespace, 162 | widgetName: name, 163 | widgetFullName: fullName 164 | } ); 165 | 166 | // If this widget is being redefined then we need to find all widgets that 167 | // are inheriting from it and redefine all of them so that they inherit from 168 | // the new version of this widget. We're essentially trying to replace one 169 | // level in the prototype chain. 170 | if ( existingConstructor ) { 171 | $.each( existingConstructor._childConstructors, function( i, child ) { 172 | var childPrototype = child.prototype; 173 | 174 | // Redefine the child widget using the same prototype that was 175 | // originally used, but inherit from the new version of the base 176 | $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, 177 | child._proto ); 178 | } ); 179 | 180 | // Remove the list of existing child constructors from the old constructor 181 | // so the old child constructors can be garbage collected 182 | delete existingConstructor._childConstructors; 183 | } else { 184 | base._childConstructors.push( constructor ); 185 | } 186 | 187 | $.widget.bridge( name, constructor ); 188 | 189 | return constructor; 190 | }; 191 | 192 | $.widget.extend = function( target ) { 193 | var input = widgetSlice.call( arguments, 1 ); 194 | var inputIndex = 0; 195 | var inputLength = input.length; 196 | var key; 197 | var value; 198 | 199 | for ( ; inputIndex < inputLength; inputIndex++ ) { 200 | for ( key in input[ inputIndex ] ) { 201 | value = input[ inputIndex ][ key ]; 202 | if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 203 | 204 | // Clone objects 205 | if ( $.isPlainObject( value ) ) { 206 | target[ key ] = $.isPlainObject( target[ key ] ) ? 207 | $.widget.extend( {}, target[ key ], value ) : 208 | 209 | // Don't extend strings, arrays, etc. with objects 210 | $.widget.extend( {}, value ); 211 | 212 | // Copy everything else by reference 213 | } else { 214 | target[ key ] = value; 215 | } 216 | } 217 | } 218 | } 219 | return target; 220 | }; 221 | 222 | $.widget.bridge = function( name, object ) { 223 | var fullName = object.prototype.widgetFullName || name; 224 | $.fn[ name ] = function( options ) { 225 | var isMethodCall = typeof options === "string"; 226 | var args = widgetSlice.call( arguments, 1 ); 227 | var returnValue = this; 228 | 229 | if ( isMethodCall ) { 230 | 231 | // If this is an empty collection, we need to have the instance method 232 | // return undefined instead of the jQuery instance 233 | if ( !this.length && options === "instance" ) { 234 | returnValue = undefined; 235 | } else { 236 | this.each( function() { 237 | var methodValue; 238 | var instance = $.data( this, fullName ); 239 | 240 | if ( options === "instance" ) { 241 | returnValue = instance; 242 | return false; 243 | } 244 | 245 | if ( !instance ) { 246 | return $.error( "cannot call methods on " + name + 247 | " prior to initialization; " + 248 | "attempted to call method '" + options + "'" ); 249 | } 250 | 251 | if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { 252 | return $.error( "no such method '" + options + "' for " + name + 253 | " widget instance" ); 254 | } 255 | 256 | methodValue = instance[ options ].apply( instance, args ); 257 | 258 | if ( methodValue !== instance && methodValue !== undefined ) { 259 | returnValue = methodValue && methodValue.jquery ? 260 | returnValue.pushStack( methodValue.get() ) : 261 | methodValue; 262 | return false; 263 | } 264 | } ); 265 | } 266 | } else { 267 | 268 | // Allow multiple hashes to be passed on init 269 | if ( args.length ) { 270 | options = $.widget.extend.apply( null, [ options ].concat( args ) ); 271 | } 272 | 273 | this.each( function() { 274 | var instance = $.data( this, fullName ); 275 | if ( instance ) { 276 | instance.option( options || {} ); 277 | if ( instance._init ) { 278 | instance._init(); 279 | } 280 | } else { 281 | $.data( this, fullName, new object( options, this ) ); 282 | } 283 | } ); 284 | } 285 | 286 | return returnValue; 287 | }; 288 | }; 289 | 290 | $.Widget = function( /* options, element */ ) {}; 291 | $.Widget._childConstructors = []; 292 | 293 | $.Widget.prototype = { 294 | widgetName: "widget", 295 | widgetEventPrefix: "", 296 | defaultElement: "
", 297 | 298 | options: { 299 | classes: {}, 300 | disabled: false, 301 | 302 | // Callbacks 303 | create: null 304 | }, 305 | 306 | _createWidget: function( options, element ) { 307 | element = $( element || this.defaultElement || this )[ 0 ]; 308 | this.element = $( element ); 309 | this.uuid = widgetUuid++; 310 | this.eventNamespace = "." + this.widgetName + this.uuid; 311 | 312 | this.bindings = $(); 313 | this.hoverable = $(); 314 | this.focusable = $(); 315 | this.classesElementLookup = {}; 316 | 317 | if ( element !== this ) { 318 | $.data( element, this.widgetFullName, this ); 319 | this._on( true, this.element, { 320 | remove: function( event ) { 321 | if ( event.target === element ) { 322 | this.destroy(); 323 | } 324 | } 325 | } ); 326 | this.document = $( element.style ? 327 | 328 | // Element within the document 329 | element.ownerDocument : 330 | 331 | // Element is window or document 332 | element.document || element ); 333 | this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); 334 | } 335 | 336 | this.options = $.widget.extend( {}, 337 | this.options, 338 | this._getCreateOptions(), 339 | options ); 340 | 341 | this._create(); 342 | 343 | if ( this.options.disabled ) { 344 | this._setOptionDisabled( this.options.disabled ); 345 | } 346 | 347 | this._trigger( "create", null, this._getCreateEventData() ); 348 | this._init(); 349 | }, 350 | 351 | _getCreateOptions: function() { 352 | return {}; 353 | }, 354 | 355 | _getCreateEventData: $.noop, 356 | 357 | _create: $.noop, 358 | 359 | _init: $.noop, 360 | 361 | destroy: function() { 362 | var that = this; 363 | 364 | this._destroy(); 365 | $.each( this.classesElementLookup, function( key, value ) { 366 | that._removeClass( value, key ); 367 | } ); 368 | 369 | // We can probably remove the unbind calls in 2.0 370 | // all event bindings should go through this._on() 371 | this.element 372 | .off( this.eventNamespace ) 373 | .removeData( this.widgetFullName ); 374 | this.widget() 375 | .off( this.eventNamespace ) 376 | .removeAttr( "aria-disabled" ); 377 | 378 | // Clean up events and states 379 | this.bindings.off( this.eventNamespace ); 380 | }, 381 | 382 | _destroy: $.noop, 383 | 384 | widget: function() { 385 | return this.element; 386 | }, 387 | 388 | option: function( key, value ) { 389 | var options = key; 390 | var parts; 391 | var curOption; 392 | var i; 393 | 394 | if ( arguments.length === 0 ) { 395 | 396 | // Don't return a reference to the internal hash 397 | return $.widget.extend( {}, this.options ); 398 | } 399 | 400 | if ( typeof key === "string" ) { 401 | 402 | // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 403 | options = {}; 404 | parts = key.split( "." ); 405 | key = parts.shift(); 406 | if ( parts.length ) { 407 | curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 408 | for ( i = 0; i < parts.length - 1; i++ ) { 409 | curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 410 | curOption = curOption[ parts[ i ] ]; 411 | } 412 | key = parts.pop(); 413 | if ( arguments.length === 1 ) { 414 | return curOption[ key ] === undefined ? null : curOption[ key ]; 415 | } 416 | curOption[ key ] = value; 417 | } else { 418 | if ( arguments.length === 1 ) { 419 | return this.options[ key ] === undefined ? null : this.options[ key ]; 420 | } 421 | options[ key ] = value; 422 | } 423 | } 424 | 425 | this._setOptions( options ); 426 | 427 | return this; 428 | }, 429 | 430 | _setOptions: function( options ) { 431 | var key; 432 | 433 | for ( key in options ) { 434 | this._setOption( key, options[ key ] ); 435 | } 436 | 437 | return this; 438 | }, 439 | 440 | _setOption: function( key, value ) { 441 | if ( key === "classes" ) { 442 | this._setOptionClasses( value ); 443 | } 444 | 445 | this.options[ key ] = value; 446 | 447 | if ( key === "disabled" ) { 448 | this._setOptionDisabled( value ); 449 | } 450 | 451 | return this; 452 | }, 453 | 454 | _setOptionClasses: function( value ) { 455 | var classKey, elements, currentElements; 456 | 457 | for ( classKey in value ) { 458 | currentElements = this.classesElementLookup[ classKey ]; 459 | if ( value[ classKey ] === this.options.classes[ classKey ] || 460 | !currentElements || 461 | !currentElements.length ) { 462 | continue; 463 | } 464 | 465 | // We are doing this to create a new jQuery object because the _removeClass() call 466 | // on the next line is going to destroy the reference to the current elements being 467 | // tracked. We need to save a copy of this collection so that we can add the new classes 468 | // below. 469 | elements = $( currentElements.get() ); 470 | this._removeClass( currentElements, classKey ); 471 | 472 | // We don't use _addClass() here, because that uses this.options.classes 473 | // for generating the string of classes. We want to use the value passed in from 474 | // _setOption(), this is the new value of the classes option which was passed to 475 | // _setOption(). We pass this value directly to _classes(). 476 | elements.addClass( this._classes( { 477 | element: elements, 478 | keys: classKey, 479 | classes: value, 480 | add: true 481 | } ) ); 482 | } 483 | }, 484 | 485 | _setOptionDisabled: function( value ) { 486 | this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); 487 | 488 | // If the widget is becoming disabled, then nothing is interactive 489 | if ( value ) { 490 | this._removeClass( this.hoverable, null, "ui-state-hover" ); 491 | this._removeClass( this.focusable, null, "ui-state-focus" ); 492 | } 493 | }, 494 | 495 | enable: function() { 496 | return this._setOptions( { disabled: false } ); 497 | }, 498 | 499 | disable: function() { 500 | return this._setOptions( { disabled: true } ); 501 | }, 502 | 503 | _classes: function( options ) { 504 | var full = []; 505 | var that = this; 506 | 507 | options = $.extend( { 508 | element: this.element, 509 | classes: this.options.classes || {} 510 | }, options ); 511 | 512 | function processClassString( classes, checkOption ) { 513 | var current, i; 514 | for ( i = 0; i < classes.length; i++ ) { 515 | current = that.classesElementLookup[ classes[ i ] ] || $(); 516 | if ( options.add ) { 517 | current = $( $.unique( current.get().concat( options.element.get() ) ) ); 518 | } else { 519 | current = $( current.not( options.element ).get() ); 520 | } 521 | that.classesElementLookup[ classes[ i ] ] = current; 522 | full.push( classes[ i ] ); 523 | if ( checkOption && options.classes[ classes[ i ] ] ) { 524 | full.push( options.classes[ classes[ i ] ] ); 525 | } 526 | } 527 | } 528 | 529 | this._on( options.element, { 530 | "remove": "_untrackClassesElement" 531 | } ); 532 | 533 | if ( options.keys ) { 534 | processClassString( options.keys.match( /\S+/g ) || [], true ); 535 | } 536 | if ( options.extra ) { 537 | processClassString( options.extra.match( /\S+/g ) || [] ); 538 | } 539 | 540 | return full.join( " " ); 541 | }, 542 | 543 | _untrackClassesElement: function( event ) { 544 | var that = this; 545 | $.each( that.classesElementLookup, function( key, value ) { 546 | if ( $.inArray( event.target, value ) !== -1 ) { 547 | that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); 548 | } 549 | } ); 550 | }, 551 | 552 | _removeClass: function( element, keys, extra ) { 553 | return this._toggleClass( element, keys, extra, false ); 554 | }, 555 | 556 | _addClass: function( element, keys, extra ) { 557 | return this._toggleClass( element, keys, extra, true ); 558 | }, 559 | 560 | _toggleClass: function( element, keys, extra, add ) { 561 | add = ( typeof add === "boolean" ) ? add : extra; 562 | var shift = ( typeof element === "string" || element === null ), 563 | options = { 564 | extra: shift ? keys : extra, 565 | keys: shift ? element : keys, 566 | element: shift ? this.element : element, 567 | add: add 568 | }; 569 | options.element.toggleClass( this._classes( options ), add ); 570 | return this; 571 | }, 572 | 573 | _on: function( suppressDisabledCheck, element, handlers ) { 574 | var delegateElement; 575 | var instance = this; 576 | 577 | // No suppressDisabledCheck flag, shuffle arguments 578 | if ( typeof suppressDisabledCheck !== "boolean" ) { 579 | handlers = element; 580 | element = suppressDisabledCheck; 581 | suppressDisabledCheck = false; 582 | } 583 | 584 | // No element argument, shuffle and use this.element 585 | if ( !handlers ) { 586 | handlers = element; 587 | element = this.element; 588 | delegateElement = this.widget(); 589 | } else { 590 | element = delegateElement = $( element ); 591 | this.bindings = this.bindings.add( element ); 592 | } 593 | 594 | $.each( handlers, function( event, handler ) { 595 | function handlerProxy() { 596 | 597 | // Allow widgets to customize the disabled handling 598 | // - disabled as an array instead of boolean 599 | // - disabled class as method for disabling individual parts 600 | if ( !suppressDisabledCheck && 601 | ( instance.options.disabled === true || 602 | $( this ).hasClass( "ui-state-disabled" ) ) ) { 603 | return; 604 | } 605 | return ( typeof handler === "string" ? instance[ handler ] : handler ) 606 | .apply( instance, arguments ); 607 | } 608 | 609 | // Copy the guid so direct unbinding works 610 | if ( typeof handler !== "string" ) { 611 | handlerProxy.guid = handler.guid = 612 | handler.guid || handlerProxy.guid || $.guid++; 613 | } 614 | 615 | var match = event.match( /^([\w:-]*)\s*(.*)$/ ); 616 | var eventName = match[ 1 ] + instance.eventNamespace; 617 | var selector = match[ 2 ]; 618 | 619 | if ( selector ) { 620 | delegateElement.on( eventName, selector, handlerProxy ); 621 | } else { 622 | element.on( eventName, handlerProxy ); 623 | } 624 | } ); 625 | }, 626 | 627 | _off: function( element, eventName ) { 628 | eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + 629 | this.eventNamespace; 630 | element.off( eventName ).off( eventName ); 631 | 632 | // Clear the stack to avoid memory leaks (#10056) 633 | this.bindings = $( this.bindings.not( element ).get() ); 634 | this.focusable = $( this.focusable.not( element ).get() ); 635 | this.hoverable = $( this.hoverable.not( element ).get() ); 636 | }, 637 | 638 | _delay: function( handler, delay ) { 639 | function handlerProxy() { 640 | return ( typeof handler === "string" ? instance[ handler ] : handler ) 641 | .apply( instance, arguments ); 642 | } 643 | var instance = this; 644 | return setTimeout( handlerProxy, delay || 0 ); 645 | }, 646 | 647 | _hoverable: function( element ) { 648 | this.hoverable = this.hoverable.add( element ); 649 | this._on( element, { 650 | mouseenter: function( event ) { 651 | this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); 652 | }, 653 | mouseleave: function( event ) { 654 | this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); 655 | } 656 | } ); 657 | }, 658 | 659 | _focusable: function( element ) { 660 | this.focusable = this.focusable.add( element ); 661 | this._on( element, { 662 | focusin: function( event ) { 663 | this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); 664 | }, 665 | focusout: function( event ) { 666 | this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); 667 | } 668 | } ); 669 | }, 670 | 671 | _trigger: function( type, event, data ) { 672 | var prop, orig; 673 | var callback = this.options[ type ]; 674 | 675 | data = data || {}; 676 | event = $.Event( event ); 677 | event.type = ( type === this.widgetEventPrefix ? 678 | type : 679 | this.widgetEventPrefix + type ).toLowerCase(); 680 | 681 | // The original event may come from any element 682 | // so we need to reset the target on the new event 683 | event.target = this.element[ 0 ]; 684 | 685 | // Copy original event properties over to the new event 686 | orig = event.originalEvent; 687 | if ( orig ) { 688 | for ( prop in orig ) { 689 | if ( !( prop in event ) ) { 690 | event[ prop ] = orig[ prop ]; 691 | } 692 | } 693 | } 694 | 695 | this.element.trigger( event, data ); 696 | return !( $.isFunction( callback ) && 697 | callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || 698 | event.isDefaultPrevented() ); 699 | } 700 | }; 701 | 702 | $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 703 | $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 704 | if ( typeof options === "string" ) { 705 | options = { effect: options }; 706 | } 707 | 708 | var hasOptions; 709 | var effectName = !options ? 710 | method : 711 | options === true || typeof options === "number" ? 712 | defaultEffect : 713 | options.effect || defaultEffect; 714 | 715 | options = options || {}; 716 | if ( typeof options === "number" ) { 717 | options = { duration: options }; 718 | } 719 | 720 | hasOptions = !$.isEmptyObject( options ); 721 | options.complete = callback; 722 | 723 | if ( options.delay ) { 724 | element.delay( options.delay ); 725 | } 726 | 727 | if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 728 | element[ method ]( options ); 729 | } else if ( effectName !== method && element[ effectName ] ) { 730 | element[ effectName ]( options.duration, options.easing, callback ); 731 | } else { 732 | element.queue( function( next ) { 733 | $( this )[ method ](); 734 | if ( callback ) { 735 | callback.call( element[ 0 ] ); 736 | } 737 | next(); 738 | } ); 739 | } 740 | }; 741 | } ); 742 | 743 | var widget = $.widget; 744 | 745 | 746 | /*! 747 | * jQuery UI :data 1.12.1 748 | * http://jqueryui.com 749 | * 750 | * Copyright jQuery Foundation and other contributors 751 | * Released under the MIT license. 752 | * http://jquery.org/license 753 | */ 754 | 755 | //>>label: :data Selector 756 | //>>group: Core 757 | //>>description: Selects elements which have data stored under the specified key. 758 | //>>docs: http://api.jqueryui.com/data-selector/ 759 | 760 | 761 | var data = $.extend( $.expr[ ":" ], { 762 | data: $.expr.createPseudo ? 763 | $.expr.createPseudo( function( dataName ) { 764 | return function( elem ) { 765 | return !!$.data( elem, dataName ); 766 | }; 767 | } ) : 768 | 769 | // Support: jQuery <1.8 770 | function( elem, i, match ) { 771 | return !!$.data( elem, match[ 3 ] ); 772 | } 773 | } ); 774 | 775 | /*! 776 | * jQuery UI Scroll Parent 1.12.1 777 | * http://jqueryui.com 778 | * 779 | * Copyright jQuery Foundation and other contributors 780 | * Released under the MIT license. 781 | * http://jquery.org/license 782 | */ 783 | 784 | //>>label: scrollParent 785 | //>>group: Core 786 | //>>description: Get the closest ancestor element that is scrollable. 787 | //>>docs: http://api.jqueryui.com/scrollParent/ 788 | 789 | 790 | 791 | var scrollParent = $.fn.scrollParent = function( includeHidden ) { 792 | var position = this.css( "position" ), 793 | excludeStaticParent = position === "absolute", 794 | overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, 795 | scrollParent = this.parents().filter( function() { 796 | var parent = $( this ); 797 | if ( excludeStaticParent && parent.css( "position" ) === "static" ) { 798 | return false; 799 | } 800 | return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + 801 | parent.css( "overflow-x" ) ); 802 | } ).eq( 0 ); 803 | 804 | return position === "fixed" || !scrollParent.length ? 805 | $( this[ 0 ].ownerDocument || document ) : 806 | scrollParent; 807 | }; 808 | 809 | 810 | 811 | 812 | // This file is deprecated 813 | var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); 814 | 815 | /*! 816 | * jQuery UI Mouse 1.12.1 817 | * http://jqueryui.com 818 | * 819 | * Copyright jQuery Foundation and other contributors 820 | * Released under the MIT license. 821 | * http://jquery.org/license 822 | */ 823 | 824 | //>>label: Mouse 825 | //>>group: Widgets 826 | //>>description: Abstracts mouse-based interactions to assist in creating certain widgets. 827 | //>>docs: http://api.jqueryui.com/mouse/ 828 | 829 | 830 | 831 | var mouseHandled = false; 832 | $( document ).on( "mouseup", function() { 833 | mouseHandled = false; 834 | } ); 835 | 836 | var widgetsMouse = $.widget( "ui.mouse", { 837 | version: "1.12.1", 838 | options: { 839 | cancel: "input, textarea, button, select, option", 840 | distance: 1, 841 | delay: 0 842 | }, 843 | _mouseInit: function() { 844 | var that = this; 845 | 846 | this.element 847 | .on( "mousedown." + this.widgetName, function( event ) { 848 | return that._mouseDown( event ); 849 | } ) 850 | .on( "click." + this.widgetName, function( event ) { 851 | if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { 852 | $.removeData( event.target, that.widgetName + ".preventClickEvent" ); 853 | event.stopImmediatePropagation(); 854 | return false; 855 | } 856 | } ); 857 | 858 | this.started = false; 859 | }, 860 | 861 | // TODO: make sure destroying one instance of mouse doesn't mess with 862 | // other instances of mouse 863 | _mouseDestroy: function() { 864 | this.element.off( "." + this.widgetName ); 865 | if ( this._mouseMoveDelegate ) { 866 | this.document 867 | .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 868 | .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 869 | } 870 | }, 871 | 872 | _mouseDown: function( event ) { 873 | 874 | // don't let more than one widget handle mouseStart 875 | if ( mouseHandled ) { 876 | return; 877 | } 878 | 879 | this._mouseMoved = false; 880 | 881 | // We may have missed mouseup (out of window) 882 | ( this._mouseStarted && this._mouseUp( event ) ); 883 | 884 | this._mouseDownEvent = event; 885 | 886 | var that = this, 887 | btnIsLeft = ( event.which === 1 ), 888 | 889 | // event.target.nodeName works around a bug in IE 8 with 890 | // disabled inputs (#7620) 891 | elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ? 892 | $( event.target ).closest( this.options.cancel ).length : false ); 893 | if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) { 894 | return true; 895 | } 896 | 897 | this.mouseDelayMet = !this.options.delay; 898 | if ( !this.mouseDelayMet ) { 899 | this._mouseDelayTimer = setTimeout( function() { 900 | that.mouseDelayMet = true; 901 | }, this.options.delay ); 902 | } 903 | 904 | if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 905 | this._mouseStarted = ( this._mouseStart( event ) !== false ); 906 | if ( !this._mouseStarted ) { 907 | event.preventDefault(); 908 | return true; 909 | } 910 | } 911 | 912 | // Click event may never have fired (Gecko & Opera) 913 | if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { 914 | $.removeData( event.target, this.widgetName + ".preventClickEvent" ); 915 | } 916 | 917 | // These delegates are required to keep context 918 | this._mouseMoveDelegate = function( event ) { 919 | return that._mouseMove( event ); 920 | }; 921 | this._mouseUpDelegate = function( event ) { 922 | return that._mouseUp( event ); 923 | }; 924 | 925 | this.document 926 | .on( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 927 | .on( "mouseup." + this.widgetName, this._mouseUpDelegate ); 928 | 929 | event.preventDefault(); 930 | 931 | mouseHandled = true; 932 | return true; 933 | }, 934 | 935 | _mouseMove: function( event ) { 936 | 937 | // Only check for mouseups outside the document if you've moved inside the document 938 | // at least once. This prevents the firing of mouseup in the case of IE<9, which will 939 | // fire a mousemove event if content is placed under the cursor. See #7778 940 | // Support: IE <9 941 | if ( this._mouseMoved ) { 942 | 943 | // IE mouseup check - mouseup happened when mouse was out of window 944 | if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && 945 | !event.button ) { 946 | return this._mouseUp( event ); 947 | 948 | // Iframe mouseup check - mouseup occurred in another document 949 | } else if ( !event.which ) { 950 | 951 | // Support: Safari <=8 - 9 952 | // Safari sets which to 0 if you press any of the following keys 953 | // during a drag (#14461) 954 | if ( event.originalEvent.altKey || event.originalEvent.ctrlKey || 955 | event.originalEvent.metaKey || event.originalEvent.shiftKey ) { 956 | this.ignoreMissingWhich = true; 957 | } else if ( !this.ignoreMissingWhich ) { 958 | return this._mouseUp( event ); 959 | } 960 | } 961 | } 962 | 963 | if ( event.which || event.button ) { 964 | this._mouseMoved = true; 965 | } 966 | 967 | if ( this._mouseStarted ) { 968 | this._mouseDrag( event ); 969 | return event.preventDefault(); 970 | } 971 | 972 | if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 973 | this._mouseStarted = 974 | ( this._mouseStart( this._mouseDownEvent, event ) !== false ); 975 | ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) ); 976 | } 977 | 978 | return !this._mouseStarted; 979 | }, 980 | 981 | _mouseUp: function( event ) { 982 | this.document 983 | .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 984 | .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 985 | 986 | if ( this._mouseStarted ) { 987 | this._mouseStarted = false; 988 | 989 | if ( event.target === this._mouseDownEvent.target ) { 990 | $.data( event.target, this.widgetName + ".preventClickEvent", true ); 991 | } 992 | 993 | this._mouseStop( event ); 994 | } 995 | 996 | if ( this._mouseDelayTimer ) { 997 | clearTimeout( this._mouseDelayTimer ); 998 | delete this._mouseDelayTimer; 999 | } 1000 | 1001 | this.ignoreMissingWhich = false; 1002 | mouseHandled = false; 1003 | event.preventDefault(); 1004 | }, 1005 | 1006 | _mouseDistanceMet: function( event ) { 1007 | return ( Math.max( 1008 | Math.abs( this._mouseDownEvent.pageX - event.pageX ), 1009 | Math.abs( this._mouseDownEvent.pageY - event.pageY ) 1010 | ) >= this.options.distance 1011 | ); 1012 | }, 1013 | 1014 | _mouseDelayMet: function( /* event */ ) { 1015 | return this.mouseDelayMet; 1016 | }, 1017 | 1018 | // These are placeholder methods, to be overriden by extending plugin 1019 | _mouseStart: function( /* event */ ) {}, 1020 | _mouseDrag: function( /* event */ ) {}, 1021 | _mouseStop: function( /* event */ ) {}, 1022 | _mouseCapture: function( /* event */ ) { return true; } 1023 | } ); 1024 | 1025 | 1026 | /*! 1027 | * jQuery UI Sortable 1.12.1 1028 | * http://jqueryui.com 1029 | * 1030 | * Copyright jQuery Foundation and other contributors 1031 | * Released under the MIT license. 1032 | * http://jquery.org/license 1033 | */ 1034 | 1035 | //>>label: Sortable 1036 | //>>group: Interactions 1037 | //>>description: Enables items in a list to be sorted using the mouse. 1038 | //>>docs: http://api.jqueryui.com/sortable/ 1039 | //>>demos: http://jqueryui.com/sortable/ 1040 | //>>css.structure: ../../themes/base/sortable.css 1041 | 1042 | 1043 | 1044 | var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, { 1045 | version: "1.12.1", 1046 | widgetEventPrefix: "sort", 1047 | ready: false, 1048 | options: { 1049 | appendTo: "parent", 1050 | axis: false, 1051 | connectWith: false, 1052 | containment: false, 1053 | cursor: "auto", 1054 | cursorAt: false, 1055 | dropOnEmpty: true, 1056 | forcePlaceholderSize: false, 1057 | forceHelperSize: false, 1058 | grid: false, 1059 | handle: false, 1060 | helper: "original", 1061 | items: "> *", 1062 | opacity: false, 1063 | placeholder: false, 1064 | revert: false, 1065 | scroll: true, 1066 | scrollSensitivity: 20, 1067 | scrollSpeed: 20, 1068 | scope: "default", 1069 | tolerance: "intersect", 1070 | zIndex: 1000, 1071 | 1072 | // Callbacks 1073 | activate: null, 1074 | beforeStop: null, 1075 | change: null, 1076 | deactivate: null, 1077 | out: null, 1078 | over: null, 1079 | receive: null, 1080 | remove: null, 1081 | sort: null, 1082 | start: null, 1083 | stop: null, 1084 | update: null 1085 | }, 1086 | 1087 | _isOverAxis: function( x, reference, size ) { 1088 | return ( x >= reference ) && ( x < ( reference + size ) ); 1089 | }, 1090 | 1091 | _isFloating: function( item ) { 1092 | return ( /left|right/ ).test( item.css( "float" ) ) || 1093 | ( /inline|table-cell/ ).test( item.css( "display" ) ); 1094 | }, 1095 | 1096 | _create: function() { 1097 | this.containerCache = {}; 1098 | this._addClass( "ui-sortable" ); 1099 | 1100 | //Get the items 1101 | this.refresh(); 1102 | 1103 | //Let's determine the parent's offset 1104 | this.offset = this.element.offset(); 1105 | 1106 | //Initialize mouse events for interaction 1107 | this._mouseInit(); 1108 | 1109 | this._setHandleClassName(); 1110 | 1111 | //We're ready to go 1112 | this.ready = true; 1113 | 1114 | }, 1115 | 1116 | _setOption: function( key, value ) { 1117 | this._super( key, value ); 1118 | 1119 | if ( key === "handle" ) { 1120 | this._setHandleClassName(); 1121 | } 1122 | }, 1123 | 1124 | _setHandleClassName: function() { 1125 | var that = this; 1126 | this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" ); 1127 | $.each( this.items, function() { 1128 | that._addClass( 1129 | this.instance.options.handle ? 1130 | this.item.find( this.instance.options.handle ) : 1131 | this.item, 1132 | "ui-sortable-handle" 1133 | ); 1134 | } ); 1135 | }, 1136 | 1137 | _destroy: function() { 1138 | this._mouseDestroy(); 1139 | 1140 | for ( var i = this.items.length - 1; i >= 0; i-- ) { 1141 | this.items[ i ].item.removeData( this.widgetName + "-item" ); 1142 | } 1143 | 1144 | return this; 1145 | }, 1146 | 1147 | _mouseCapture: function( event, overrideHandle ) { 1148 | var currentItem = null, 1149 | validHandle = false, 1150 | that = this; 1151 | 1152 | if ( this.reverting ) { 1153 | return false; 1154 | } 1155 | 1156 | if ( this.options.disabled || this.options.type === "static" ) { 1157 | return false; 1158 | } 1159 | 1160 | //We have to refresh the items data once first 1161 | this._refreshItems( event ); 1162 | 1163 | //Find out if the clicked node (or one of its parents) is a actual item in this.items 1164 | $( event.target ).parents().each( function() { 1165 | if ( $.data( this, that.widgetName + "-item" ) === that ) { 1166 | currentItem = $( this ); 1167 | return false; 1168 | } 1169 | } ); 1170 | if ( $.data( event.target, that.widgetName + "-item" ) === that ) { 1171 | currentItem = $( event.target ); 1172 | } 1173 | 1174 | if ( !currentItem ) { 1175 | return false; 1176 | } 1177 | if ( this.options.handle && !overrideHandle ) { 1178 | $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() { 1179 | if ( this === event.target ) { 1180 | validHandle = true; 1181 | } 1182 | } ); 1183 | if ( !validHandle ) { 1184 | return false; 1185 | } 1186 | } 1187 | 1188 | this.currentItem = currentItem; 1189 | this._removeCurrentsFromItems(); 1190 | return true; 1191 | 1192 | }, 1193 | 1194 | _mouseStart: function( event, overrideHandle, noActivation ) { 1195 | 1196 | var i, body, 1197 | o = this.options; 1198 | 1199 | this.currentContainer = this; 1200 | 1201 | //We only need to call refreshPositions, because the refreshItems call has been moved to 1202 | // mouseCapture 1203 | this.refreshPositions(); 1204 | 1205 | //Create and append the visible helper 1206 | this.helper = this._createHelper( event ); 1207 | 1208 | //Cache the helper size 1209 | this._cacheHelperProportions(); 1210 | 1211 | /* 1212 | * - Position generation - 1213 | * This block generates everything position related - it's the core of draggables. 1214 | */ 1215 | 1216 | //Cache the margins of the original element 1217 | this._cacheMargins(); 1218 | 1219 | //Get the next scrolling parent 1220 | this.scrollParent = this.helper.scrollParent(); 1221 | 1222 | //The element's absolute position on the page minus margins 1223 | this.offset = this.currentItem.offset(); 1224 | this.offset = { 1225 | top: this.offset.top - this.margins.top, 1226 | left: this.offset.left - this.margins.left 1227 | }; 1228 | 1229 | $.extend( this.offset, { 1230 | click: { //Where the click happened, relative to the element 1231 | left: event.pageX - this.offset.left, 1232 | top: event.pageY - this.offset.top 1233 | }, 1234 | parent: this._getParentOffset(), 1235 | 1236 | // This is a relative to absolute position minus the actual position calculation - 1237 | // only used for relative positioned helper 1238 | relative: this._getRelativeOffset() 1239 | } ); 1240 | 1241 | // Only after we got the offset, we can change the helper's position to absolute 1242 | // TODO: Still need to figure out a way to make relative sorting possible 1243 | this.helper.css( "position", "absolute" ); 1244 | this.cssPosition = this.helper.css( "position" ); 1245 | 1246 | //Generate the original position 1247 | this.originalPosition = this._generatePosition( event ); 1248 | this.originalPageX = event.pageX; 1249 | this.originalPageY = event.pageY; 1250 | 1251 | //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 1252 | ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) ); 1253 | 1254 | //Cache the former DOM position 1255 | this.domPosition = { 1256 | prev: this.currentItem.prev()[ 0 ], 1257 | parent: this.currentItem.parent()[ 0 ] 1258 | }; 1259 | 1260 | // If the helper is not the original, hide the original so it's not playing any role during 1261 | // the drag, won't cause anything bad this way 1262 | if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 1263 | this.currentItem.hide(); 1264 | } 1265 | 1266 | //Create the placeholder 1267 | this._createPlaceholder(); 1268 | 1269 | //Set a containment if given in the options 1270 | if ( o.containment ) { 1271 | this._setContainment(); 1272 | } 1273 | 1274 | if ( o.cursor && o.cursor !== "auto" ) { // cursor option 1275 | body = this.document.find( "body" ); 1276 | 1277 | // Support: IE 1278 | this.storedCursor = body.css( "cursor" ); 1279 | body.css( "cursor", o.cursor ); 1280 | 1281 | this.storedStylesheet = 1282 | $( "" ).appendTo( body ); 1283 | } 1284 | 1285 | if ( o.opacity ) { // opacity option 1286 | if ( this.helper.css( "opacity" ) ) { 1287 | this._storedOpacity = this.helper.css( "opacity" ); 1288 | } 1289 | this.helper.css( "opacity", o.opacity ); 1290 | } 1291 | 1292 | if ( o.zIndex ) { // zIndex option 1293 | if ( this.helper.css( "zIndex" ) ) { 1294 | this._storedZIndex = this.helper.css( "zIndex" ); 1295 | } 1296 | this.helper.css( "zIndex", o.zIndex ); 1297 | } 1298 | 1299 | //Prepare scrolling 1300 | if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 1301 | this.scrollParent[ 0 ].tagName !== "HTML" ) { 1302 | this.overflowOffset = this.scrollParent.offset(); 1303 | } 1304 | 1305 | //Call callbacks 1306 | this._trigger( "start", event, this._uiHash() ); 1307 | 1308 | //Recache the helper size 1309 | if ( !this._preserveHelperProportions ) { 1310 | this._cacheHelperProportions(); 1311 | } 1312 | 1313 | //Post "activate" events to possible containers 1314 | if ( !noActivation ) { 1315 | for ( i = this.containers.length - 1; i >= 0; i-- ) { 1316 | this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); 1317 | } 1318 | } 1319 | 1320 | //Prepare possible droppables 1321 | if ( $.ui.ddmanager ) { 1322 | $.ui.ddmanager.current = this; 1323 | } 1324 | 1325 | if ( $.ui.ddmanager && !o.dropBehaviour ) { 1326 | $.ui.ddmanager.prepareOffsets( this, event ); 1327 | } 1328 | 1329 | this.dragging = true; 1330 | 1331 | this._addClass( this.helper, "ui-sortable-helper" ); 1332 | 1333 | // Execute the drag once - this causes the helper not to be visiblebefore getting its 1334 | // correct position 1335 | this._mouseDrag( event ); 1336 | return true; 1337 | 1338 | }, 1339 | 1340 | _mouseDrag: function( event ) { 1341 | var i, item, itemElement, intersection, 1342 | o = this.options, 1343 | scrolled = false; 1344 | 1345 | //Compute the helpers position 1346 | this.position = this._generatePosition( event ); 1347 | this.positionAbs = this._convertPositionTo( "absolute" ); 1348 | 1349 | if ( !this.lastPositionAbs ) { 1350 | this.lastPositionAbs = this.positionAbs; 1351 | } 1352 | 1353 | //Do scrolling 1354 | if ( this.options.scroll ) { 1355 | if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 1356 | this.scrollParent[ 0 ].tagName !== "HTML" ) { 1357 | 1358 | if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) - 1359 | event.pageY < o.scrollSensitivity ) { 1360 | this.scrollParent[ 0 ].scrollTop = 1361 | scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed; 1362 | } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) { 1363 | this.scrollParent[ 0 ].scrollTop = 1364 | scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed; 1365 | } 1366 | 1367 | if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) - 1368 | event.pageX < o.scrollSensitivity ) { 1369 | this.scrollParent[ 0 ].scrollLeft = scrolled = 1370 | this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed; 1371 | } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) { 1372 | this.scrollParent[ 0 ].scrollLeft = scrolled = 1373 | this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed; 1374 | } 1375 | 1376 | } else { 1377 | 1378 | if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) { 1379 | scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed ); 1380 | } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) < 1381 | o.scrollSensitivity ) { 1382 | scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed ); 1383 | } 1384 | 1385 | if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) { 1386 | scrolled = this.document.scrollLeft( 1387 | this.document.scrollLeft() - o.scrollSpeed 1388 | ); 1389 | } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) < 1390 | o.scrollSensitivity ) { 1391 | scrolled = this.document.scrollLeft( 1392 | this.document.scrollLeft() + o.scrollSpeed 1393 | ); 1394 | } 1395 | 1396 | } 1397 | 1398 | if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) { 1399 | $.ui.ddmanager.prepareOffsets( this, event ); 1400 | } 1401 | } 1402 | 1403 | //Regenerate the absolute position used for position checks 1404 | this.positionAbs = this._convertPositionTo( "absolute" ); 1405 | 1406 | //Set the helper position 1407 | if ( !this.options.axis || this.options.axis !== "y" ) { 1408 | this.helper[ 0 ].style.left = this.position.left + "px"; 1409 | } 1410 | if ( !this.options.axis || this.options.axis !== "x" ) { 1411 | this.helper[ 0 ].style.top = this.position.top + "px"; 1412 | } 1413 | 1414 | //Rearrange 1415 | for ( i = this.items.length - 1; i >= 0; i-- ) { 1416 | 1417 | //Cache variables and intersection, continue if no intersection 1418 | item = this.items[ i ]; 1419 | itemElement = item.item[ 0 ]; 1420 | intersection = this._intersectsWithPointer( item ); 1421 | if ( !intersection ) { 1422 | continue; 1423 | } 1424 | 1425 | // Only put the placeholder inside the current Container, skip all 1426 | // items from other containers. This works because when moving 1427 | // an item from one container to another the 1428 | // currentContainer is switched before the placeholder is moved. 1429 | // 1430 | // Without this, moving items in "sub-sortables" can cause 1431 | // the placeholder to jitter between the outer and inner container. 1432 | if ( item.instance !== this.currentContainer ) { 1433 | continue; 1434 | } 1435 | 1436 | // Cannot intersect with itself 1437 | // no useless actions that have been done before 1438 | // no action if the item moved is the parent of the item checked 1439 | if ( itemElement !== this.currentItem[ 0 ] && 1440 | this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement && 1441 | !$.contains( this.placeholder[ 0 ], itemElement ) && 1442 | ( this.options.type === "semi-dynamic" ? 1443 | !$.contains( this.element[ 0 ], itemElement ) : 1444 | true 1445 | ) 1446 | ) { 1447 | 1448 | this.direction = intersection === 1 ? "down" : "up"; 1449 | 1450 | if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) { 1451 | this._rearrange( event, item ); 1452 | } else { 1453 | break; 1454 | } 1455 | 1456 | this._trigger( "change", event, this._uiHash() ); 1457 | break; 1458 | } 1459 | } 1460 | 1461 | //Post events to containers 1462 | this._contactContainers( event ); 1463 | 1464 | //Interconnect with droppables 1465 | if ( $.ui.ddmanager ) { 1466 | $.ui.ddmanager.drag( this, event ); 1467 | } 1468 | 1469 | //Call callbacks 1470 | this._trigger( "sort", event, this._uiHash() ); 1471 | 1472 | this.lastPositionAbs = this.positionAbs; 1473 | return false; 1474 | 1475 | }, 1476 | 1477 | _mouseStop: function( event, noPropagation ) { 1478 | 1479 | if ( !event ) { 1480 | return; 1481 | } 1482 | 1483 | //If we are using droppables, inform the manager about the drop 1484 | if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 1485 | $.ui.ddmanager.drop( this, event ); 1486 | } 1487 | 1488 | if ( this.options.revert ) { 1489 | var that = this, 1490 | cur = this.placeholder.offset(), 1491 | axis = this.options.axis, 1492 | animation = {}; 1493 | 1494 | if ( !axis || axis === "x" ) { 1495 | animation.left = cur.left - this.offset.parent.left - this.margins.left + 1496 | ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 1497 | 0 : 1498 | this.offsetParent[ 0 ].scrollLeft 1499 | ); 1500 | } 1501 | if ( !axis || axis === "y" ) { 1502 | animation.top = cur.top - this.offset.parent.top - this.margins.top + 1503 | ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 1504 | 0 : 1505 | this.offsetParent[ 0 ].scrollTop 1506 | ); 1507 | } 1508 | this.reverting = true; 1509 | $( this.helper ).animate( 1510 | animation, 1511 | parseInt( this.options.revert, 10 ) || 500, 1512 | function() { 1513 | that._clear( event ); 1514 | } 1515 | ); 1516 | } else { 1517 | this._clear( event, noPropagation ); 1518 | } 1519 | 1520 | return false; 1521 | 1522 | }, 1523 | 1524 | cancel: function() { 1525 | 1526 | if ( this.dragging ) { 1527 | 1528 | this._mouseUp( new $.Event( "mouseup", { target: null } ) ); 1529 | 1530 | if ( this.options.helper === "original" ) { 1531 | this.currentItem.css( this._storedCSS ); 1532 | this._removeClass( this.currentItem, "ui-sortable-helper" ); 1533 | } else { 1534 | this.currentItem.show(); 1535 | } 1536 | 1537 | //Post deactivating events to containers 1538 | for ( var i = this.containers.length - 1; i >= 0; i-- ) { 1539 | this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) ); 1540 | if ( this.containers[ i ].containerCache.over ) { 1541 | this.containers[ i ]._trigger( "out", null, this._uiHash( this ) ); 1542 | this.containers[ i ].containerCache.over = 0; 1543 | } 1544 | } 1545 | 1546 | } 1547 | 1548 | if ( this.placeholder ) { 1549 | 1550 | //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 1551 | // it unbinds ALL events from the original node! 1552 | if ( this.placeholder[ 0 ].parentNode ) { 1553 | this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 1554 | } 1555 | if ( this.options.helper !== "original" && this.helper && 1556 | this.helper[ 0 ].parentNode ) { 1557 | this.helper.remove(); 1558 | } 1559 | 1560 | $.extend( this, { 1561 | helper: null, 1562 | dragging: false, 1563 | reverting: false, 1564 | _noFinalSort: null 1565 | } ); 1566 | 1567 | if ( this.domPosition.prev ) { 1568 | $( this.domPosition.prev ).after( this.currentItem ); 1569 | } else { 1570 | $( this.domPosition.parent ).prepend( this.currentItem ); 1571 | } 1572 | } 1573 | 1574 | return this; 1575 | 1576 | }, 1577 | 1578 | serialize: function( o ) { 1579 | 1580 | var items = this._getItemsAsjQuery( o && o.connected ), 1581 | str = []; 1582 | o = o || {}; 1583 | 1584 | $( items ).each( function() { 1585 | var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" ) 1586 | .match( o.expression || ( /(.+)[\-=_](.+)/ ) ); 1587 | if ( res ) { 1588 | str.push( 1589 | ( o.key || res[ 1 ] + "[]" ) + 1590 | "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) ); 1591 | } 1592 | } ); 1593 | 1594 | if ( !str.length && o.key ) { 1595 | str.push( o.key + "=" ); 1596 | } 1597 | 1598 | return str.join( "&" ); 1599 | 1600 | }, 1601 | 1602 | toArray: function( o ) { 1603 | 1604 | var items = this._getItemsAsjQuery( o && o.connected ), 1605 | ret = []; 1606 | 1607 | o = o || {}; 1608 | 1609 | items.each( function() { 1610 | ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" ); 1611 | } ); 1612 | return ret; 1613 | 1614 | }, 1615 | 1616 | /* Be careful with the following core functions */ 1617 | _intersectsWith: function( item ) { 1618 | 1619 | var x1 = this.positionAbs.left, 1620 | x2 = x1 + this.helperProportions.width, 1621 | y1 = this.positionAbs.top, 1622 | y2 = y1 + this.helperProportions.height, 1623 | l = item.left, 1624 | r = l + item.width, 1625 | t = item.top, 1626 | b = t + item.height, 1627 | dyClick = this.offset.click.top, 1628 | dxClick = this.offset.click.left, 1629 | isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && 1630 | ( y1 + dyClick ) < b ), 1631 | isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && 1632 | ( x1 + dxClick ) < r ), 1633 | isOverElement = isOverElementHeight && isOverElementWidth; 1634 | 1635 | if ( this.options.tolerance === "pointer" || 1636 | this.options.forcePointerForContainers || 1637 | ( this.options.tolerance !== "pointer" && 1638 | this.helperProportions[ this.floating ? "width" : "height" ] > 1639 | item[ this.floating ? "width" : "height" ] ) 1640 | ) { 1641 | return isOverElement; 1642 | } else { 1643 | 1644 | return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half 1645 | x2 - ( this.helperProportions.width / 2 ) < r && // Left Half 1646 | t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half 1647 | y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half 1648 | 1649 | } 1650 | }, 1651 | 1652 | _intersectsWithPointer: function( item ) { 1653 | var verticalDirection, horizontalDirection, 1654 | isOverElementHeight = ( this.options.axis === "x" ) || 1655 | this._isOverAxis( 1656 | this.positionAbs.top + this.offset.click.top, item.top, item.height ), 1657 | isOverElementWidth = ( this.options.axis === "y" ) || 1658 | this._isOverAxis( 1659 | this.positionAbs.left + this.offset.click.left, item.left, item.width ), 1660 | isOverElement = isOverElementHeight && isOverElementWidth; 1661 | 1662 | if ( !isOverElement ) { 1663 | return false; 1664 | } 1665 | 1666 | verticalDirection = this._getDragVerticalDirection(); 1667 | horizontalDirection = this._getDragHorizontalDirection(); 1668 | 1669 | return this.floating ? 1670 | ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) 1671 | : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) ); 1672 | 1673 | }, 1674 | 1675 | _intersectsWithSides: function( item ) { 1676 | 1677 | var isOverBottomHalf = this._isOverAxis( this.positionAbs.top + 1678 | this.offset.click.top, item.top + ( item.height / 2 ), item.height ), 1679 | isOverRightHalf = this._isOverAxis( this.positionAbs.left + 1680 | this.offset.click.left, item.left + ( item.width / 2 ), item.width ), 1681 | verticalDirection = this._getDragVerticalDirection(), 1682 | horizontalDirection = this._getDragHorizontalDirection(); 1683 | 1684 | if ( this.floating && horizontalDirection ) { 1685 | return ( ( horizontalDirection === "right" && isOverRightHalf ) || 1686 | ( horizontalDirection === "left" && !isOverRightHalf ) ); 1687 | } else { 1688 | return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) || 1689 | ( verticalDirection === "up" && !isOverBottomHalf ) ); 1690 | } 1691 | 1692 | }, 1693 | 1694 | _getDragVerticalDirection: function() { 1695 | var delta = this.positionAbs.top - this.lastPositionAbs.top; 1696 | return delta !== 0 && ( delta > 0 ? "down" : "up" ); 1697 | }, 1698 | 1699 | _getDragHorizontalDirection: function() { 1700 | var delta = this.positionAbs.left - this.lastPositionAbs.left; 1701 | return delta !== 0 && ( delta > 0 ? "right" : "left" ); 1702 | }, 1703 | 1704 | refresh: function( event ) { 1705 | this._refreshItems( event ); 1706 | this._setHandleClassName(); 1707 | this.refreshPositions(); 1708 | return this; 1709 | }, 1710 | 1711 | _connectWith: function() { 1712 | var options = this.options; 1713 | return options.connectWith.constructor === String ? 1714 | [ options.connectWith ] : 1715 | options.connectWith; 1716 | }, 1717 | 1718 | _getItemsAsjQuery: function( connected ) { 1719 | 1720 | var i, j, cur, inst, 1721 | items = [], 1722 | queries = [], 1723 | connectWith = this._connectWith(); 1724 | 1725 | if ( connectWith && connected ) { 1726 | for ( i = connectWith.length - 1; i >= 0; i-- ) { 1727 | cur = $( connectWith[ i ], this.document[ 0 ] ); 1728 | for ( j = cur.length - 1; j >= 0; j-- ) { 1729 | inst = $.data( cur[ j ], this.widgetFullName ); 1730 | if ( inst && inst !== this && !inst.options.disabled ) { 1731 | queries.push( [ $.isFunction( inst.options.items ) ? 1732 | inst.options.items.call( inst.element ) : 1733 | $( inst.options.items, inst.element ) 1734 | .not( ".ui-sortable-helper" ) 1735 | .not( ".ui-sortable-placeholder" ), inst ] ); 1736 | } 1737 | } 1738 | } 1739 | } 1740 | 1741 | queries.push( [ $.isFunction( this.options.items ) ? 1742 | this.options.items 1743 | .call( this.element, null, { options: this.options, item: this.currentItem } ) : 1744 | $( this.options.items, this.element ) 1745 | .not( ".ui-sortable-helper" ) 1746 | .not( ".ui-sortable-placeholder" ), this ] ); 1747 | 1748 | function addItems() { 1749 | items.push( this ); 1750 | } 1751 | for ( i = queries.length - 1; i >= 0; i-- ) { 1752 | queries[ i ][ 0 ].each( addItems ); 1753 | } 1754 | 1755 | return $( items ); 1756 | 1757 | }, 1758 | 1759 | _removeCurrentsFromItems: function() { 1760 | 1761 | var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" ); 1762 | 1763 | this.items = $.grep( this.items, function( item ) { 1764 | for ( var j = 0; j < list.length; j++ ) { 1765 | if ( list[ j ] === item.item[ 0 ] ) { 1766 | return false; 1767 | } 1768 | } 1769 | return true; 1770 | } ); 1771 | 1772 | }, 1773 | 1774 | _refreshItems: function( event ) { 1775 | 1776 | this.items = []; 1777 | this.containers = [ this ]; 1778 | 1779 | var i, j, cur, inst, targetData, _queries, item, queriesLength, 1780 | items = this.items, 1781 | queries = [ [ $.isFunction( this.options.items ) ? 1782 | this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) : 1783 | $( this.options.items, this.element ), this ] ], 1784 | connectWith = this._connectWith(); 1785 | 1786 | //Shouldn't be run the first time through due to massive slow-down 1787 | if ( connectWith && this.ready ) { 1788 | for ( i = connectWith.length - 1; i >= 0; i-- ) { 1789 | cur = $( connectWith[ i ], this.document[ 0 ] ); 1790 | for ( j = cur.length - 1; j >= 0; j-- ) { 1791 | inst = $.data( cur[ j ], this.widgetFullName ); 1792 | if ( inst && inst !== this && !inst.options.disabled ) { 1793 | queries.push( [ $.isFunction( inst.options.items ) ? 1794 | inst.options.items 1795 | .call( inst.element[ 0 ], event, { item: this.currentItem } ) : 1796 | $( inst.options.items, inst.element ), inst ] ); 1797 | this.containers.push( inst ); 1798 | } 1799 | } 1800 | } 1801 | } 1802 | 1803 | for ( i = queries.length - 1; i >= 0; i-- ) { 1804 | targetData = queries[ i ][ 1 ]; 1805 | _queries = queries[ i ][ 0 ]; 1806 | 1807 | for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) { 1808 | item = $( _queries[ j ] ); 1809 | 1810 | // Data for target checking (mouse manager) 1811 | item.data( this.widgetName + "-item", targetData ); 1812 | 1813 | items.push( { 1814 | item: item, 1815 | instance: targetData, 1816 | width: 0, height: 0, 1817 | left: 0, top: 0 1818 | } ); 1819 | } 1820 | } 1821 | 1822 | }, 1823 | 1824 | refreshPositions: function( fast ) { 1825 | 1826 | // Determine whether items are being displayed horizontally 1827 | this.floating = this.items.length ? 1828 | this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) : 1829 | false; 1830 | 1831 | //This has to be redone because due to the item being moved out/into the offsetParent, 1832 | // the offsetParent's position will change 1833 | if ( this.offsetParent && this.helper ) { 1834 | this.offset.parent = this._getParentOffset(); 1835 | } 1836 | 1837 | var i, item, t, p; 1838 | 1839 | for ( i = this.items.length - 1; i >= 0; i-- ) { 1840 | item = this.items[ i ]; 1841 | 1842 | //We ignore calculating positions of all connected containers when we're not over them 1843 | if ( item.instance !== this.currentContainer && this.currentContainer && 1844 | item.item[ 0 ] !== this.currentItem[ 0 ] ) { 1845 | continue; 1846 | } 1847 | 1848 | t = this.options.toleranceElement ? 1849 | $( this.options.toleranceElement, item.item ) : 1850 | item.item; 1851 | 1852 | if ( !fast ) { 1853 | item.width = t.outerWidth(); 1854 | item.height = t.outerHeight(); 1855 | } 1856 | 1857 | p = t.offset(); 1858 | item.left = p.left; 1859 | item.top = p.top; 1860 | } 1861 | 1862 | if ( this.options.custom && this.options.custom.refreshContainers ) { 1863 | this.options.custom.refreshContainers.call( this ); 1864 | } else { 1865 | for ( i = this.containers.length - 1; i >= 0; i-- ) { 1866 | p = this.containers[ i ].element.offset(); 1867 | this.containers[ i ].containerCache.left = p.left; 1868 | this.containers[ i ].containerCache.top = p.top; 1869 | this.containers[ i ].containerCache.width = 1870 | this.containers[ i ].element.outerWidth(); 1871 | this.containers[ i ].containerCache.height = 1872 | this.containers[ i ].element.outerHeight(); 1873 | } 1874 | } 1875 | 1876 | return this; 1877 | }, 1878 | 1879 | _createPlaceholder: function( that ) { 1880 | that = that || this; 1881 | var className, 1882 | o = that.options; 1883 | 1884 | if ( !o.placeholder || o.placeholder.constructor === String ) { 1885 | className = o.placeholder; 1886 | o.placeholder = { 1887 | element: function() { 1888 | 1889 | var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(), 1890 | element = $( "<" + nodeName + ">", that.document[ 0 ] ); 1891 | 1892 | that._addClass( element, "ui-sortable-placeholder", 1893 | className || that.currentItem[ 0 ].className ) 1894 | ._removeClass( element, "ui-sortable-helper" ); 1895 | 1896 | if ( nodeName === "tbody" ) { 1897 | that._createTrPlaceholder( 1898 | that.currentItem.find( "tr" ).eq( 0 ), 1899 | $( "", that.document[ 0 ] ).appendTo( element ) 1900 | ); 1901 | } else if ( nodeName === "tr" ) { 1902 | that._createTrPlaceholder( that.currentItem, element ); 1903 | } else if ( nodeName === "img" ) { 1904 | element.attr( "src", that.currentItem.attr( "src" ) ); 1905 | } 1906 | 1907 | if ( !className ) { 1908 | element.css( "visibility", "hidden" ); 1909 | } 1910 | 1911 | return element; 1912 | }, 1913 | update: function( container, p ) { 1914 | 1915 | // 1. If a className is set as 'placeholder option, we don't force sizes - 1916 | // the class is responsible for that 1917 | // 2. The option 'forcePlaceholderSize can be enabled to force it even if a 1918 | // class name is specified 1919 | if ( className && !o.forcePlaceholderSize ) { 1920 | return; 1921 | } 1922 | 1923 | //If the element doesn't have a actual height by itself (without styles coming 1924 | // from a stylesheet), it receives the inline height from the dragged item 1925 | if ( !p.height() ) { 1926 | p.height( 1927 | that.currentItem.innerHeight() - 1928 | parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) - 1929 | parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) ); 1930 | } 1931 | if ( !p.width() ) { 1932 | p.width( 1933 | that.currentItem.innerWidth() - 1934 | parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) - 1935 | parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) ); 1936 | } 1937 | } 1938 | }; 1939 | } 1940 | 1941 | //Create the placeholder 1942 | that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) ); 1943 | 1944 | //Append it after the actual current item 1945 | that.currentItem.after( that.placeholder ); 1946 | 1947 | //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) 1948 | o.placeholder.update( that, that.placeholder ); 1949 | 1950 | }, 1951 | 1952 | _createTrPlaceholder: function( sourceTr, targetTr ) { 1953 | var that = this; 1954 | 1955 | sourceTr.children().each( function() { 1956 | $( " ", that.document[ 0 ] ) 1957 | .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) 1958 | .appendTo( targetTr ); 1959 | } ); 1960 | }, 1961 | 1962 | _contactContainers: function( event ) { 1963 | var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, 1964 | floating, axis, 1965 | innermostContainer = null, 1966 | innermostIndex = null; 1967 | 1968 | // Get innermost container that intersects with item 1969 | for ( i = this.containers.length - 1; i >= 0; i-- ) { 1970 | 1971 | // Never consider a container that's located within the item itself 1972 | if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) { 1973 | continue; 1974 | } 1975 | 1976 | if ( this._intersectsWith( this.containers[ i ].containerCache ) ) { 1977 | 1978 | // If we've already found a container and it's more "inner" than this, then continue 1979 | if ( innermostContainer && 1980 | $.contains( 1981 | this.containers[ i ].element[ 0 ], 1982 | innermostContainer.element[ 0 ] ) ) { 1983 | continue; 1984 | } 1985 | 1986 | innermostContainer = this.containers[ i ]; 1987 | innermostIndex = i; 1988 | 1989 | } else { 1990 | 1991 | // container doesn't intersect. trigger "out" event if necessary 1992 | if ( this.containers[ i ].containerCache.over ) { 1993 | this.containers[ i ]._trigger( "out", event, this._uiHash( this ) ); 1994 | this.containers[ i ].containerCache.over = 0; 1995 | } 1996 | } 1997 | 1998 | } 1999 | 2000 | // If no intersecting containers found, return 2001 | if ( !innermostContainer ) { 2002 | return; 2003 | } 2004 | 2005 | // Move the item into the container if it's not there already 2006 | if ( this.containers.length === 1 ) { 2007 | if ( !this.containers[ innermostIndex ].containerCache.over ) { 2008 | this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 2009 | this.containers[ innermostIndex ].containerCache.over = 1; 2010 | } 2011 | } else { 2012 | 2013 | // When entering a new container, we will find the item with the least distance and 2014 | // append our item near it 2015 | dist = 10000; 2016 | itemWithLeastDistance = null; 2017 | floating = innermostContainer.floating || this._isFloating( this.currentItem ); 2018 | posProperty = floating ? "left" : "top"; 2019 | sizeProperty = floating ? "width" : "height"; 2020 | axis = floating ? "pageX" : "pageY"; 2021 | 2022 | for ( j = this.items.length - 1; j >= 0; j-- ) { 2023 | if ( !$.contains( 2024 | this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] ) 2025 | ) { 2026 | continue; 2027 | } 2028 | if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) { 2029 | continue; 2030 | } 2031 | 2032 | cur = this.items[ j ].item.offset()[ posProperty ]; 2033 | nearBottom = false; 2034 | if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { 2035 | nearBottom = true; 2036 | } 2037 | 2038 | if ( Math.abs( event[ axis ] - cur ) < dist ) { 2039 | dist = Math.abs( event[ axis ] - cur ); 2040 | itemWithLeastDistance = this.items[ j ]; 2041 | this.direction = nearBottom ? "up" : "down"; 2042 | } 2043 | } 2044 | 2045 | //Check if dropOnEmpty is enabled 2046 | if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) { 2047 | return; 2048 | } 2049 | 2050 | if ( this.currentContainer === this.containers[ innermostIndex ] ) { 2051 | if ( !this.currentContainer.containerCache.over ) { 2052 | this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() ); 2053 | this.currentContainer.containerCache.over = 1; 2054 | } 2055 | return; 2056 | } 2057 | 2058 | itemWithLeastDistance ? 2059 | this._rearrange( event, itemWithLeastDistance, null, true ) : 2060 | this._rearrange( event, null, this.containers[ innermostIndex ].element, true ); 2061 | this._trigger( "change", event, this._uiHash() ); 2062 | this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) ); 2063 | this.currentContainer = this.containers[ innermostIndex ]; 2064 | 2065 | //Update the placeholder 2066 | this.options.placeholder.update( this.currentContainer, this.placeholder ); 2067 | 2068 | this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 2069 | this.containers[ innermostIndex ].containerCache.over = 1; 2070 | } 2071 | 2072 | }, 2073 | 2074 | _createHelper: function( event ) { 2075 | 2076 | var o = this.options, 2077 | helper = $.isFunction( o.helper ) ? 2078 | $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) : 2079 | ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem ); 2080 | 2081 | //Add the helper to the DOM if that didn't happen already 2082 | if ( !helper.parents( "body" ).length ) { 2083 | $( o.appendTo !== "parent" ? 2084 | o.appendTo : 2085 | this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] ); 2086 | } 2087 | 2088 | if ( helper[ 0 ] === this.currentItem[ 0 ] ) { 2089 | this._storedCSS = { 2090 | width: this.currentItem[ 0 ].style.width, 2091 | height: this.currentItem[ 0 ].style.height, 2092 | position: this.currentItem.css( "position" ), 2093 | top: this.currentItem.css( "top" ), 2094 | left: this.currentItem.css( "left" ) 2095 | }; 2096 | } 2097 | 2098 | if ( !helper[ 0 ].style.width || o.forceHelperSize ) { 2099 | helper.width( this.currentItem.width() ); 2100 | } 2101 | if ( !helper[ 0 ].style.height || o.forceHelperSize ) { 2102 | helper.height( this.currentItem.height() ); 2103 | } 2104 | 2105 | return helper; 2106 | 2107 | }, 2108 | 2109 | _adjustOffsetFromHelper: function( obj ) { 2110 | if ( typeof obj === "string" ) { 2111 | obj = obj.split( " " ); 2112 | } 2113 | if ( $.isArray( obj ) ) { 2114 | obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 2115 | } 2116 | if ( "left" in obj ) { 2117 | this.offset.click.left = obj.left + this.margins.left; 2118 | } 2119 | if ( "right" in obj ) { 2120 | this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 2121 | } 2122 | if ( "top" in obj ) { 2123 | this.offset.click.top = obj.top + this.margins.top; 2124 | } 2125 | if ( "bottom" in obj ) { 2126 | this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 2127 | } 2128 | }, 2129 | 2130 | _getParentOffset: function() { 2131 | 2132 | //Get the offsetParent and cache its position 2133 | this.offsetParent = this.helper.offsetParent(); 2134 | var po = this.offsetParent.offset(); 2135 | 2136 | // This is a special case where we need to modify a offset calculated on start, since the 2137 | // following happened: 2138 | // 1. The position of the helper is absolute, so it's position is calculated based on the 2139 | // next positioned parent 2140 | // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 2141 | // the document, which means that the scroll is included in the initial calculation of the 2142 | // offset of the parent, and never recalculated upon drag 2143 | if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] && 2144 | $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 2145 | po.left += this.scrollParent.scrollLeft(); 2146 | po.top += this.scrollParent.scrollTop(); 2147 | } 2148 | 2149 | // This needs to be actually done for all browsers, since pageX/pageY includes this 2150 | // information with an ugly IE fix 2151 | if ( this.offsetParent[ 0 ] === this.document[ 0 ].body || 2152 | ( this.offsetParent[ 0 ].tagName && 2153 | this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) { 2154 | po = { top: 0, left: 0 }; 2155 | } 2156 | 2157 | return { 2158 | top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 2159 | left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 2160 | }; 2161 | 2162 | }, 2163 | 2164 | _getRelativeOffset: function() { 2165 | 2166 | if ( this.cssPosition === "relative" ) { 2167 | var p = this.currentItem.position(); 2168 | return { 2169 | top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 2170 | this.scrollParent.scrollTop(), 2171 | left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 2172 | this.scrollParent.scrollLeft() 2173 | }; 2174 | } else { 2175 | return { top: 0, left: 0 }; 2176 | } 2177 | 2178 | }, 2179 | 2180 | _cacheMargins: function() { 2181 | this.margins = { 2182 | left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ), 2183 | top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 ) 2184 | }; 2185 | }, 2186 | 2187 | _cacheHelperProportions: function() { 2188 | this.helperProportions = { 2189 | width: this.helper.outerWidth(), 2190 | height: this.helper.outerHeight() 2191 | }; 2192 | }, 2193 | 2194 | _setContainment: function() { 2195 | 2196 | var ce, co, over, 2197 | o = this.options; 2198 | if ( o.containment === "parent" ) { 2199 | o.containment = this.helper[ 0 ].parentNode; 2200 | } 2201 | if ( o.containment === "document" || o.containment === "window" ) { 2202 | this.containment = [ 2203 | 0 - this.offset.relative.left - this.offset.parent.left, 2204 | 0 - this.offset.relative.top - this.offset.parent.top, 2205 | o.containment === "document" ? 2206 | this.document.width() : 2207 | this.window.width() - this.helperProportions.width - this.margins.left, 2208 | ( o.containment === "document" ? 2209 | ( this.document.height() || document.body.parentNode.scrollHeight ) : 2210 | this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight 2211 | ) - this.helperProportions.height - this.margins.top 2212 | ]; 2213 | } 2214 | 2215 | if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) { 2216 | ce = $( o.containment )[ 0 ]; 2217 | co = $( o.containment ).offset(); 2218 | over = ( $( ce ).css( "overflow" ) !== "hidden" ); 2219 | 2220 | this.containment = [ 2221 | co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) + 2222 | ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left, 2223 | co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) + 2224 | ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top, 2225 | co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 2226 | ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) - 2227 | ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) - 2228 | this.helperProportions.width - this.margins.left, 2229 | co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 2230 | ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) - 2231 | ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) - 2232 | this.helperProportions.height - this.margins.top 2233 | ]; 2234 | } 2235 | 2236 | }, 2237 | 2238 | _convertPositionTo: function( d, pos ) { 2239 | 2240 | if ( !pos ) { 2241 | pos = this.position; 2242 | } 2243 | var mod = d === "absolute" ? 1 : -1, 2244 | scroll = this.cssPosition === "absolute" && 2245 | !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 2246 | $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 2247 | this.offsetParent : 2248 | this.scrollParent, 2249 | scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 2250 | 2251 | return { 2252 | top: ( 2253 | 2254 | // The absolute mouse position 2255 | pos.top + 2256 | 2257 | // Only for relative positioned nodes: Relative offset from element to offset parent 2258 | this.offset.relative.top * mod + 2259 | 2260 | // The offsetParent's offset without borders (offset + border) 2261 | this.offset.parent.top * mod - 2262 | ( ( this.cssPosition === "fixed" ? 2263 | -this.scrollParent.scrollTop() : 2264 | ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod ) 2265 | ), 2266 | left: ( 2267 | 2268 | // The absolute mouse position 2269 | pos.left + 2270 | 2271 | // Only for relative positioned nodes: Relative offset from element to offset parent 2272 | this.offset.relative.left * mod + 2273 | 2274 | // The offsetParent's offset without borders (offset + border) 2275 | this.offset.parent.left * mod - 2276 | ( ( this.cssPosition === "fixed" ? 2277 | -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : 2278 | scroll.scrollLeft() ) * mod ) 2279 | ) 2280 | }; 2281 | 2282 | }, 2283 | 2284 | _generatePosition: function( event ) { 2285 | 2286 | var top, left, 2287 | o = this.options, 2288 | pageX = event.pageX, 2289 | pageY = event.pageY, 2290 | scroll = this.cssPosition === "absolute" && 2291 | !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 2292 | $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 2293 | this.offsetParent : 2294 | this.scrollParent, 2295 | scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 2296 | 2297 | // This is another very weird special case that only happens for relative elements: 2298 | // 1. If the css position is relative 2299 | // 2. and the scroll parent is the document or similar to the offset parent 2300 | // we have to refresh the relative offset during the scroll so there are no jumps 2301 | if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 2302 | this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) { 2303 | this.offset.relative = this._getRelativeOffset(); 2304 | } 2305 | 2306 | /* 2307 | * - Position constraining - 2308 | * Constrain the position to a mix of grid, containment. 2309 | */ 2310 | 2311 | if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options 2312 | 2313 | if ( this.containment ) { 2314 | if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) { 2315 | pageX = this.containment[ 0 ] + this.offset.click.left; 2316 | } 2317 | if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) { 2318 | pageY = this.containment[ 1 ] + this.offset.click.top; 2319 | } 2320 | if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) { 2321 | pageX = this.containment[ 2 ] + this.offset.click.left; 2322 | } 2323 | if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) { 2324 | pageY = this.containment[ 3 ] + this.offset.click.top; 2325 | } 2326 | } 2327 | 2328 | if ( o.grid ) { 2329 | top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) / 2330 | o.grid[ 1 ] ) * o.grid[ 1 ]; 2331 | pageY = this.containment ? 2332 | ( ( top - this.offset.click.top >= this.containment[ 1 ] && 2333 | top - this.offset.click.top <= this.containment[ 3 ] ) ? 2334 | top : 2335 | ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ? 2336 | top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : 2337 | top; 2338 | 2339 | left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) / 2340 | o.grid[ 0 ] ) * o.grid[ 0 ]; 2341 | pageX = this.containment ? 2342 | ( ( left - this.offset.click.left >= this.containment[ 0 ] && 2343 | left - this.offset.click.left <= this.containment[ 2 ] ) ? 2344 | left : 2345 | ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ? 2346 | left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : 2347 | left; 2348 | } 2349 | 2350 | } 2351 | 2352 | return { 2353 | top: ( 2354 | 2355 | // The absolute mouse position 2356 | pageY - 2357 | 2358 | // Click offset (relative to the element) 2359 | this.offset.click.top - 2360 | 2361 | // Only for relative positioned nodes: Relative offset from element to offset parent 2362 | this.offset.relative.top - 2363 | 2364 | // The offsetParent's offset without borders (offset + border) 2365 | this.offset.parent.top + 2366 | ( ( this.cssPosition === "fixed" ? 2367 | -this.scrollParent.scrollTop() : 2368 | ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) ) 2369 | ), 2370 | left: ( 2371 | 2372 | // The absolute mouse position 2373 | pageX - 2374 | 2375 | // Click offset (relative to the element) 2376 | this.offset.click.left - 2377 | 2378 | // Only for relative positioned nodes: Relative offset from element to offset parent 2379 | this.offset.relative.left - 2380 | 2381 | // The offsetParent's offset without borders (offset + border) 2382 | this.offset.parent.left + 2383 | ( ( this.cssPosition === "fixed" ? 2384 | -this.scrollParent.scrollLeft() : 2385 | scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) 2386 | ) 2387 | }; 2388 | 2389 | }, 2390 | 2391 | _rearrange: function( event, i, a, hardRefresh ) { 2392 | 2393 | a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) : 2394 | i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ], 2395 | ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) ); 2396 | 2397 | //Various things done here to improve the performance: 2398 | // 1. we create a setTimeout, that calls refreshPositions 2399 | // 2. on the instance, we have a counter variable, that get's higher after every append 2400 | // 3. on the local scope, we copy the counter variable, and check in the timeout, 2401 | // if it's still the same 2402 | // 4. this lets only the last addition to the timeout stack through 2403 | this.counter = this.counter ? ++this.counter : 1; 2404 | var counter = this.counter; 2405 | 2406 | this._delay( function() { 2407 | if ( counter === this.counter ) { 2408 | 2409 | //Precompute after each DOM insertion, NOT on mousemove 2410 | this.refreshPositions( !hardRefresh ); 2411 | } 2412 | } ); 2413 | 2414 | }, 2415 | 2416 | _clear: function( event, noPropagation ) { 2417 | 2418 | this.reverting = false; 2419 | 2420 | // We delay all events that have to be triggered to after the point where the placeholder 2421 | // has been removed and everything else normalized again 2422 | var i, 2423 | delayedTriggers = []; 2424 | 2425 | // We first have to update the dom position of the actual currentItem 2426 | // Note: don't do it if the current item is already removed (by a user), or it gets 2427 | // reappended (see #4088) 2428 | if ( !this._noFinalSort && this.currentItem.parent().length ) { 2429 | this.placeholder.before( this.currentItem ); 2430 | } 2431 | this._noFinalSort = null; 2432 | 2433 | if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) { 2434 | for ( i in this._storedCSS ) { 2435 | if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) { 2436 | this._storedCSS[ i ] = ""; 2437 | } 2438 | } 2439 | this.currentItem.css( this._storedCSS ); 2440 | this._removeClass( this.currentItem, "ui-sortable-helper" ); 2441 | } else { 2442 | this.currentItem.show(); 2443 | } 2444 | 2445 | if ( this.fromOutside && !noPropagation ) { 2446 | delayedTriggers.push( function( event ) { 2447 | this._trigger( "receive", event, this._uiHash( this.fromOutside ) ); 2448 | } ); 2449 | } 2450 | if ( ( this.fromOutside || 2451 | this.domPosition.prev !== 2452 | this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] || 2453 | this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) { 2454 | 2455 | // Trigger update callback if the DOM position has changed 2456 | delayedTriggers.push( function( event ) { 2457 | this._trigger( "update", event, this._uiHash() ); 2458 | } ); 2459 | } 2460 | 2461 | // Check if the items Container has Changed and trigger appropriate 2462 | // events. 2463 | if ( this !== this.currentContainer ) { 2464 | if ( !noPropagation ) { 2465 | delayedTriggers.push( function( event ) { 2466 | this._trigger( "remove", event, this._uiHash() ); 2467 | } ); 2468 | delayedTriggers.push( ( function( c ) { 2469 | return function( event ) { 2470 | c._trigger( "receive", event, this._uiHash( this ) ); 2471 | }; 2472 | } ).call( this, this.currentContainer ) ); 2473 | delayedTriggers.push( ( function( c ) { 2474 | return function( event ) { 2475 | c._trigger( "update", event, this._uiHash( this ) ); 2476 | }; 2477 | } ).call( this, this.currentContainer ) ); 2478 | } 2479 | } 2480 | 2481 | //Post events to containers 2482 | function delayEvent( type, instance, container ) { 2483 | return function( event ) { 2484 | container._trigger( type, event, instance._uiHash( instance ) ); 2485 | }; 2486 | } 2487 | for ( i = this.containers.length - 1; i >= 0; i-- ) { 2488 | if ( !noPropagation ) { 2489 | delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); 2490 | } 2491 | if ( this.containers[ i ].containerCache.over ) { 2492 | delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); 2493 | this.containers[ i ].containerCache.over = 0; 2494 | } 2495 | } 2496 | 2497 | //Do what was originally in plugins 2498 | if ( this.storedCursor ) { 2499 | this.document.find( "body" ).css( "cursor", this.storedCursor ); 2500 | this.storedStylesheet.remove(); 2501 | } 2502 | if ( this._storedOpacity ) { 2503 | this.helper.css( "opacity", this._storedOpacity ); 2504 | } 2505 | if ( this._storedZIndex ) { 2506 | this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex ); 2507 | } 2508 | 2509 | this.dragging = false; 2510 | 2511 | if ( !noPropagation ) { 2512 | this._trigger( "beforeStop", event, this._uiHash() ); 2513 | } 2514 | 2515 | //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 2516 | // it unbinds ALL events from the original node! 2517 | this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 2518 | 2519 | if ( !this.cancelHelperRemoval ) { 2520 | if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 2521 | this.helper.remove(); 2522 | } 2523 | this.helper = null; 2524 | } 2525 | 2526 | if ( !noPropagation ) { 2527 | for ( i = 0; i < delayedTriggers.length; i++ ) { 2528 | 2529 | // Trigger all delayed events 2530 | delayedTriggers[ i ].call( this, event ); 2531 | } 2532 | this._trigger( "stop", event, this._uiHash() ); 2533 | } 2534 | 2535 | this.fromOutside = false; 2536 | return !this.cancelHelperRemoval; 2537 | 2538 | }, 2539 | 2540 | _trigger: function() { 2541 | if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) { 2542 | this.cancel(); 2543 | } 2544 | }, 2545 | 2546 | _uiHash: function( _inst ) { 2547 | var inst = _inst || this; 2548 | return { 2549 | helper: inst.helper, 2550 | placeholder: inst.placeholder || $( [] ), 2551 | position: inst.position, 2552 | originalPosition: inst.originalPosition, 2553 | offset: inst.positionAbs, 2554 | item: inst.currentItem, 2555 | sender: _inst ? _inst.element : null 2556 | }; 2557 | } 2558 | 2559 | } ); 2560 | 2561 | 2562 | 2563 | 2564 | })); -------------------------------------------------------------------------------- /js/jquery-ui-sortable/jquery-ui.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2017-02-03 2 | * http://jqueryui.com 3 | * Includes: sortable.css 4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 5 | 6 | .ui-sortable-handle{-ms-touch-action:none;touch-action:none} -------------------------------------------------------------------------------- /js/jquery-ui-sortable/jquery-ui.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2017-02-03 2 | * http://jqueryui.com 3 | * Includes: widget.js, data.js, scroll-parent.js, widgets/sortable.js, widgets/mouse.js 4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 5 | 6 | (function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){t.ui=t.ui||{},t.ui.version="1.12.1";var e=0,i=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},l=e.split(".")[0];e=e.split(".")[1];var h=l+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][h.toLowerCase()]=function(e){return!!t.data(e,h)},t[l]=t[l]||{},n=t[l][e],o=t[l][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:l,widgetName:e,widgetFullName:h}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var s,n,o=i.call(arguments,1),a=0,r=o.length;r>a;a++)for(s in o[a])n=o[a][s],o[a].hasOwnProperty(s)&&void 0!==n&&(e[s]=t.isPlainObject(n)?t.isPlainObject(e[s])?t.widget.extend({},e[s],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,s){var n=s.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=i.call(arguments,1),l=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(l=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(l=i&&i.jquery?l.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):l=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new s(o,this))})),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{classes:{},disabled:!1,create:null},_createWidget:function(i,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=e++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),i),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var l=s.match(/^([\w:-]*)\s*(.*)$/),h=l[1]+o.eventNamespace,c=l[2];c?n.on(h,c,r):i.on(h,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var s=!1;t(document).on("mouseup",function(){s=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!s){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,n=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return n&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),s=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,s=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.widget("ui.sortable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(t,e,i){return t>=e&&e+i>t},_isFloating:function(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))},_create:function(){this.containerCache={},this._addClass("ui-sortable"),this.refresh(),this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(t,e){this._super(t,e),"handle"===t&&this._setHandleClassName()},_setHandleClassName:function(){var e=this;this._removeClass(this.element.find(".ui-sortable-handle"),"ui-sortable-handle"),t.each(this.items,function(){e._addClass(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item,"ui-sortable-handle")})},_destroy:function(){this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):void 0}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp(new t.Event("mouseup",{target:null})),"original"===this.options.helper?(this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,l=r+t.height,h=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+h>r&&l>s+h,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&l>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var e,i,s="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top,t.height),n="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left,t.width),o=s&&n;return o?(e=this._getDragVerticalDirection(),i=this._getDragHorizontalDirection(),this.floating?"right"===i||"down"===e?2:1:e&&("down"===e?2:1)):!1},_intersectsWithSides:function(t){var e=this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&e||"up"===s&&!e)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],l=[],h=this._connectWith();if(h&&e)for(s=h.length-1;s>=0;s--)for(o=t(h[s],this.document[0]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&l.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(l.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=l.length-1;s>=0;s--)l[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,l,h,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i],this.document[0]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,h=r.length;h>s;s++)l=t(r[s]),l.data(this.widgetName+"-item",a),c.push({item:l,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]);return e._addClass(n,"ui-sortable-placeholder",i||e.currentItem[0].className)._removeClass(n,"ui-sortable-helper"),"tbody"===s?e._createTrPlaceholder(e.currentItem.find("tr").eq(0),t("",e.document[0]).appendTo(n)):"tr"===s?e._createTrPlaceholder(e.currentItem,n):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_createTrPlaceholder:function(e,i){var s=this;e.children().each(function(){t(" ",s.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(e){var i,s,n,o,a,r,l,h,c,u,d=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!t.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(d&&t.contains(this.containers[i].element[0],d.element[0]))continue;d=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",e,this._uiHash(this)),this.containers[i].containerCache.over=0);if(d)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,o=null,c=d.floating||this._isFloating(this.currentItem),a=c?"left":"top",r=c?"width":"height",u=c?"pageX":"pageY",s=this.items.length-1;s>=0;s--)t.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(l=this.items[s].item.offset()[a],h=!1,e[u]-l>this.items[s][r]/2&&(h=!0),n>Math.abs(e[u]-l)&&(n=Math.abs(e[u]-l),o=this.items[s],this.direction=h?"up":"down"));if(!o&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;o?this._rearrange(e,o,null,!0):this._rearrange(e,null,this.containers[p].element,!0),this._trigger("change",e,this._uiHash()),this.containers[p]._trigger("change",e,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.height()||document.body.parentNode.scrollHeight:this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s} 7 | },_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,l=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.leftthis.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():l?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():l?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})}); -------------------------------------------------------------------------------- /js/jquery-ui-sortable/jquery-ui.structure.css: -------------------------------------------------------------------------------- 1 | .ui-sortable-handle { 2 | -ms-touch-action: none; 3 | touch-action: none; 4 | } 5 | -------------------------------------------------------------------------------- /js/jquery-ui-sortable/jquery-ui.structure.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2017-02-03 2 | * http://jqueryui.com 3 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 4 | 5 | .ui-sortable-handle{-ms-touch-action:none;touch-action:none} -------------------------------------------------------------------------------- /js/jquery-ui-sortable/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-ui", 3 | "title": "jQuery UI", 4 | "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.", 5 | "version": "1.12.1", 6 | "homepage": "http://jqueryui.com", 7 | "author": { 8 | "name": "jQuery Foundation and other contributors", 9 | "url": "https://github.com/jquery/jquery-ui/blob/1.12.1/AUTHORS.txt" 10 | }, 11 | "main": "ui/widget.js", 12 | "maintainers": [ 13 | { 14 | "name": "Scott González", 15 | "email": "scott.gonzalez@gmail.com", 16 | "url": "http://scottgonzalez.com" 17 | }, 18 | { 19 | "name": "Jörn Zaefferer", 20 | "email": "joern.zaefferer@gmail.com", 21 | "url": "http://bassistance.de" 22 | }, 23 | { 24 | "name": "Mike Sherov", 25 | "email": "mike.sherov@gmail.com", 26 | "url": "http://mike.sherov.com" 27 | }, 28 | { 29 | "name": "TJ VanToll", 30 | "email": "tj.vantoll@gmail.com", 31 | "url": "http://tjvantoll.com" 32 | }, 33 | { 34 | "name": "Felix Nagel", 35 | "email": "info@felixnagel.com", 36 | "url": "http://www.felixnagel.com" 37 | }, 38 | { 39 | "name": "Alex Schmitz", 40 | "email": "arschmitz@gmail.com", 41 | "url": "https://github.com/arschmitz" 42 | } 43 | ], 44 | "repository": { 45 | "type": "git", 46 | "url": "git://github.com/jquery/jquery-ui.git" 47 | }, 48 | "bugs": "https://bugs.jqueryui.com/", 49 | "license": "MIT", 50 | "scripts": { 51 | "test": "grunt" 52 | }, 53 | "dependencies": {}, 54 | "devDependencies": { 55 | "commitplease": "2.3.0", 56 | "grunt": "0.4.5", 57 | "grunt-bowercopy": "1.2.4", 58 | "grunt-cli": "0.1.13", 59 | "grunt-compare-size": "0.4.0", 60 | "grunt-contrib-concat": "0.5.1", 61 | "grunt-contrib-csslint": "0.5.0", 62 | "grunt-contrib-jshint": "0.12.0", 63 | "grunt-contrib-qunit": "1.0.1", 64 | "grunt-contrib-requirejs": "0.4.4", 65 | "grunt-contrib-uglify": "0.11.1", 66 | "grunt-git-authors": "3.1.0", 67 | "grunt-html": "6.0.0", 68 | "grunt-jscs": "2.1.0", 69 | "load-grunt-tasks": "3.4.0", 70 | "rimraf": "2.5.1", 71 | "testswarm": "1.1.0" 72 | }, 73 | "keywords": [] 74 | } 75 | -------------------------------------------------------------------------------- /js/layer-tree.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | //@implements {IControl} 3 | function LayerTree(options) { 4 | this.options = options; 5 | this.sources = []; 6 | } 7 | 8 | LayerTree.prototype.onAdd = function(map) { 9 | this._map = map; 10 | this._container = document.createElement('div'); 11 | this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group'; 12 | 13 | //layer manager bounding box 14 | var layerBox = document.createElement('div'); 15 | layerBox.className = 'mapboxgl-ctrl legend-container'; 16 | 17 | //legend ui 18 | var legendDiv = document.createElement('div'); 19 | legendDiv.id = 'mapboxgl-legend'; 20 | 21 | layerBox.appendChild(legendDiv); 22 | this._container.appendChild(layerBox); 23 | 24 | this.getLayers(map); 25 | return this._container; 26 | } 27 | 28 | LayerTree.prototype.onRemove = function() { 29 | this._container.parentNode.removeChild(this._container); 30 | this._map = undefined; 31 | } 32 | 33 | //get layers once they start loading 34 | LayerTree.prototype.getLayers = function(map) { 35 | var _this = this; 36 | var layers = _this.options.layers; 37 | var onClickLoad = _this.options.hasOwnProperty('onClickLoad') ? _this.options.onClickLoad : false; 38 | var sourceCollection = _this.sources; 39 | var numSources = []; 40 | 41 | map.sourceCollection = sourceCollection; 42 | map.lyrs = layers; 43 | map.onClickLoad = onClickLoad; 44 | 45 | for (var s = layers.length - 1; s >= 0; s--) { 46 | if (layers[s].hasOwnProperty('source') && $.inArray(layers[s].source, numSources) === -1) { 47 | numSources.push(layers[s].source); 48 | } else if (layers[s].hasOwnProperty('layerGroup')) { 49 | //check layerGroups for composite layer sources 50 | var layerGroup = layers[s].layerGroup; 51 | for (var c = layerGroup.length - 1; c >= 0; c--) { 52 | if ($.inArray(layerGroup[c].source, numSources) === -1) { 53 | numSources.push(layerGroup[c].source); 54 | } 55 | }; 56 | } 57 | }; 58 | 59 | var loadingSource = function(e) { 60 | var lyrGroupSource; 61 | var lyr = layers.filter(function(layer) { 62 | if (layer.hasOwnProperty('source')) { 63 | return layer.source === e.sourceId; 64 | } else if (layer.hasOwnProperty('layerGroup')) { 65 | for (var indx = layer.layerGroup.length - 1; indx >= 0; indx--) { 66 | if (layer.layerGroup[indx].source === e.sourceId) { 67 | lyrGroupSource = layer.layerGroup[indx].source; 68 | return lyrGroupSource; 69 | } 70 | } 71 | } 72 | }); 73 | 74 | if (lyr.length) { 75 | for (var l = lyr.length - 1; l >= 0; l--) { 76 | if (lyr[l] === lyr[lyr.length-1]) { 77 | if (lyrGroupSource !== undefined || lyrGroupSource !== '' || lyr.hasOwnProperty('source')) { 78 | var mapLyrObj = map.getSource(e.sourceId); 79 | sourceCollection.push(mapLyrObj); 80 | } 81 | } 82 | _this.appendLayerToLegend(map, mapLyrObj, lyr[l]); 83 | }; 84 | } 85 | 86 | if (sourceCollection.length === numSources.length) { 87 | map.off('sourcedataloading', loadingSource) 88 | //_this.loadBasemaps(map, _this.options.basemaps); 89 | _this.enableSortHandler(map, _this.loadComplete(_this, map, sourceCollection)); 90 | } 91 | } 92 | 93 | map.on('sourcedataloading', loadingSource); 94 | } 95 | 96 | //callback to append layer to legend 97 | LayerTree.prototype.appendLayerToLegend = function(map, mapLyrObj, lyr) { 98 | var legendId = '#mapboxgl-legend'; 99 | var directoryName = lyr.directory; 100 | var directoryId = directoryName.replace(/\s+/g, '-').toLowerCase(); 101 | 102 | var layerName = lyr.name; 103 | var layerId = lyr.id; 104 | var layerDiv = "
" + layerName + "
"; 105 | 106 | if ($('#' + directoryId).length) { 107 | if (!$('#' + layerId).length) { 108 | $('#' + directoryId).append(layerDiv); 109 | } 110 | } else { 111 | $(legendId).append("
" + directoryName + "