├── .gitignore ├── Cakefile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── bower.json ├── gridly.jquery.json ├── images ├── fork.png ├── tar.png └── zip.png ├── index.haml ├── index.html ├── javascripts ├── jquery.gridly.coffee ├── jquery.gridly.js ├── jquery.js ├── rainbow.js ├── sample.coffee └── sample.js ├── package.json ├── packages ├── jquery.gridly.tar └── jquery.gridly.zip └── stylesheets ├── jquery.gridly.css ├── jquery.gridly.sass ├── sample.css └── sample.sass /.gitignore: -------------------------------------------------------------------------------- 1 | .sass* -------------------------------------------------------------------------------- /Cakefile: -------------------------------------------------------------------------------- 1 | PROJECT = "jquery.gridly" 2 | 3 | {spawn, exec} = require "child_process" 4 | 5 | command = (name, args...) -> 6 | proc = spawn name, args 7 | 8 | proc.stderr.on "data", (buffer) -> 9 | console.log buffer.toString() 10 | 11 | proc.stdout.on "data", (buffer) -> 12 | console.log buffer.toString() 13 | 14 | proc.on "exit", (status) -> process.exit(1) if status != 0 15 | 16 | task "watch", "SASS and CoffeeScript", (options) -> 17 | command "sass", "--sourcemap=none", "--watch", "stylesheets:stylesheets" 18 | command "sass", "--sourcemap=none", "--watch", "spec:spec" 19 | command "coffee", "-wc", "javascripts" 20 | command "coffee", "-wc", "spec" 21 | 22 | task "compile", "HAML", (opions) -> 23 | command "haml", "index.haml", "index.html" 24 | 25 | task "package", "Package CSS and JS", (options) -> 26 | command "zip", "packages/#{PROJECT}.zip", 27 | "javascripts/#{PROJECT}.js", 28 | "stylesheets/#{PROJECT}.css", 29 | command "tar", "-cf", 30 | "packages/#{PROJECT}.tar", 31 | "javascripts/#{PROJECT}.js", 32 | "stylesheets/#{PROJECT}.css", 33 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'haml' 5 | gem 'sass' 6 | gem 'jasmine' 7 | gem 'listen' 8 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | bourbon (7.0.0) 5 | thor (~> 1.0) 6 | ffi (1.13.1) 7 | haml (5.1.2) 8 | temple (>= 0.8.0) 9 | tilt 10 | jasmine (3.5.1) 11 | jasmine-core (~> 3.5.0) 12 | phantomjs 13 | rack (>= 1.2.1) 14 | rake 15 | jasmine-core (3.5.0) 16 | listen (3.2.1) 17 | rb-fsevent (~> 0.10, >= 0.10.3) 18 | rb-inotify (~> 0.9, >= 0.9.10) 19 | neat (1.7.4) 20 | bourbon (>= 4.0) 21 | sass (>= 3.3) 22 | phantomjs (2.1.1.0) 23 | rack (2.2.3) 24 | rake (13.0.1) 25 | rb-fsevent (0.10.4) 26 | rb-inotify (0.10.1) 27 | ffi (~> 1.0) 28 | sass (3.7.4) 29 | sass-listen (~> 4.0.0) 30 | sass-listen (4.0.0) 31 | rb-fsevent (~> 0.9, >= 0.9.4) 32 | rb-inotify (~> 0.9, >= 0.9.7) 33 | temple (0.8.2) 34 | thor (1.0.1) 35 | tilt (2.0.10) 36 | 37 | PLATFORMS 38 | ruby 39 | 40 | DEPENDENCIES 41 | bourbon 42 | haml 43 | jasmine 44 | listen 45 | neat 46 | rake 47 | sass 48 | 49 | BUNDLED WITH 50 | 2.1.4 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 - 2013 Kevin Sylvestre 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery Gridly 2 | 3 | Gridly is a jQuery plugin to enable dragging and dropping as well as resizing on a grid. 4 | 5 | ## Installation 6 | 7 | To install copy the *javascripts* and *stylesheets* directories into your project and add the following snippet to the header: 8 | 9 | 10 | 11 | 12 | 13 | This plugin is also registered under http://bower.io/ to simplify integration. Try: 14 | 15 | npm install -g bower 16 | bower install gridly 17 | 18 | Lastly this plugin is registered as a https://rails-assets.org/ to simplify integration with Ruby on Rails applications: 19 | 20 | **Gemfile** 21 | 22 | + source 'https://rails-assets.org' 23 | ... 24 | + gem 'rails-assets-gridly' 25 | 26 | **application.css** 27 | 28 | /* 29 | ... 30 | *= require gridly 31 | ... 32 | */ 33 | 34 | **application.js** 35 | 36 | //= require jquery 37 | ... 38 | //= require gridly 39 | 40 | ## Examples 41 | 42 | Setting up a gridly is easy. The following snippet is a good start: 43 | 44 | 55 | 56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | 65 | 68 | 69 | ## Configuration 70 | 71 | Gridly uses a fairly standard pattern for handling grids and offers three configuration options for sizing: *base*, *gutter* and *columns*: 72 | 73 | $('.gridly').gridly({ 74 | base: 60, // px 75 | gutter: 20, // px 76 | columns: 12 77 | }); 78 | 79 | When using the drag and drop sorting callbacks can be passed in when initializing: 80 | 81 | var reordering = function($elements) { 82 | // Called before the drag and drop starts with the elements in their starting position. 83 | }; 84 | 85 | var reordered = function($elements) { 86 | // Called after the drag and drop ends with the elements in their ending position. 87 | }; 88 | 89 | $('.gridly').gridly({ 90 | callbacks: { reordering: reordering , reordered: reordered } 91 | }); 92 | 93 | 94 | $('.gridly').gridly('draggable', 'off'); // disables dragging 95 | $('.gridly').gridly('draggable', 'on); // enables dragging 96 | 97 | ## Contributing 98 | 99 | Gridly is maintained in `CoffeeScript`. All contributions need to be submitted in `CoffeeScript`. The project includes a `Cakefile` that can be used to compile all assets (see: `cake watch`). For more information about `CoffeeScript` see: 100 | 101 | - http://coffeescript.org/ 102 | - http://arcturo.github.io/library/coffeescript/ 103 | 104 | ## Status 105 | 106 | [![Status](https://travis-ci.org/ksylvest/jquery-gridly.png)](https://travis-ci.org/ksylvest/jquery-gridly) 107 | 108 | ## Copyright 109 | 110 | Copyright (c) 2013 - 2015 Kevin Sylvestre. See LICENSE for details. 111 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | 2 | begin 3 | require 'jasmine' 4 | load 'jasmine/tasks/jasmine.rake' 5 | rescue LoadError 6 | task :jasmine do 7 | abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gridly", 3 | "version": "1.3.0", 4 | "main": [ "./javascripts/jquery.gridly.js","./stylesheets/jquery.gridly.css" ], 5 | "ignore": 6 | [ 7 | "README*", 8 | "LICENSE*", 9 | "**/*.sass", 10 | "**/*.coffee", 11 | "**/sample.*", 12 | "**/rainbow.js", 13 | "**/rainbow.css", 14 | "**/jquery.js", 15 | "**/jquery.css", 16 | "samples", 17 | "spec", 18 | "bourbon", 19 | "neat", 20 | "packages", 21 | "images", 22 | "Cakefile*", 23 | "Rakefile*", 24 | "Gemfile*", 25 | ".git*", 26 | ".travis*", 27 | "*bower.json", 28 | "*jquery.json", 29 | "index*" 30 | ], 31 | "dependencies": { "jquery": "latest" } 32 | } 33 | -------------------------------------------------------------------------------- /gridly.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gridly", 3 | "title": "jQuery Gridly", 4 | "description": "Gridly is a jQuery plugin that allows for dragging and dropping as well as resizing.", 5 | "keywords": ["grid","animation"], 6 | "version": "1.3.0", 7 | "author": { 8 | "name": "Kevin Sylvestre", 9 | "email": "kevin@ksylvest.com", 10 | "url": "http://ksylvest.com/" 11 | }, 12 | "licenses": 13 | [ 14 | { 15 | "type": "MIT", 16 | "url": "https://github.com/ksylvest/jquery-gridly/LICENSE" 17 | } 18 | ], 19 | "bugs": "https://github.com/ksylvest/jquery-gridly/issues", 20 | "docs": "https://ksylvest.github.com/jquery-gridly", 21 | "homepage": "https://ksylvest.github.com/jquery-gridly", 22 | "download": "https://ksylvest.github.com/jquery-gridly", 23 | "dependencies": 24 | { 25 | "jquery": ">1.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /images/fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksylvest/jquery-gridly/65d1e4bfdc3f16cd837710d8b631b91c4db01ddc/images/fork.png -------------------------------------------------------------------------------- /images/tar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksylvest/jquery-gridly/65d1e4bfdc3f16cd837710d8b631b91c4db01ddc/images/tar.png -------------------------------------------------------------------------------- /images/zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksylvest/jquery-gridly/65d1e4bfdc3f16cd837710d8b631b91c4db01ddc/images/zip.png -------------------------------------------------------------------------------- /index.haml: -------------------------------------------------------------------------------- 1 | !!! 5 2 | %html 3 | %head 4 | %meta{ charset: "UTF-8" } 5 | %title jQuery Gridly 6 | %link{ href:"https://fonts.googleapis.com/css?family=Lato", rel: "stylesheet", type: "text/css" } 7 | %link{ href:"stylesheets/jquery.gridly.css", rel: "stylesheet", type: "text/css" } 8 | %link{ href:"stylesheets/sample.css", rel: "stylesheet", type: "text/css" } 9 | %script{ src:"javascripts/jquery.js", type: "text/javascript" } 10 | %script{ src:"javascripts/jquery.gridly.js", type: "text/javascript" } 11 | %script{ src:"javascripts/sample.js", type: "text/javascript" } 12 | %script{ src: "javascripts/rainbow.js", type: "text/javascript" } 13 | :javascript 14 | 15 | var _gaq = _gaq || []; 16 | _gaq.push(['_setAccount', 'UA-31911059-1']); 17 | _gaq.push(['_trackPageview']); 18 | 19 | (function() { 20 | var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; 21 | ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 22 | var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); 23 | })(); 24 | 25 | %body 26 | %a{ href: "https://github.com/ksylvest/jquery-gridly"} 27 | %img.fork{ src: "images/fork.png", alt: "Fork" } 28 | .content 29 | %h1 jQuery Gridly 30 | %p Gridly is a jQuery plugin to enable dragging and dropping as well as resizing on a grids. In the example below try tapping or dragging any of the bricks. 31 | %h2 Example 32 | %section.example 33 | .gridly 34 | - 20.times do 35 | .brick.small 36 | %a.delete{ href: '#' } × 37 | %p.actions 38 | %a.add.button{ href: '#' } Add 39 | %h2 Installation 40 | %p To install download one of these packages and include the jquery.gridly.js and jquery.gridly.css files in your head with the following: 41 | %section.formats 42 | .format 43 | %a.zip{ href: "packages/jquery.gridly.zip" } 44 | .format 45 | %a.tar{ href: "packages/jquery.gridly.tar" } 46 | %pre 47 | %code{ data: { language: "html" } } 48 | = preserve do 49 | :escaped 50 | 51 | 52 | 53 | %h2 Example 54 | %p Setting up a gridly is easy. The following snippet is a good start: 55 | %pre 56 | %code{ data: { language: "html" } } 57 | = preserve do 58 | :escaped 59 | 73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | 88 | %p.copy 89 | Copyright (c) 2013 - 2015 90 | %a{ href: "http://ksylvest.com/" } Kevin Sylvestre 91 | %p.links 92 | %a{ href: "https://github.com/ksylvest" } GitHub 93 | %a{ href: "https://plus.google.com/+KevinSylvestre?rel=author" } Google 94 | %a{ href: "https://twitter.com/ksylvest" } Twitter 95 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery Gridly 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 24 | 25 | 26 | 27 | 28 | Fork 29 | 30 |
31 |

jQuery Gridly

32 |

Gridly is a jQuery plugin to enable dragging and dropping as well as resizing on a grids. In the example below try tapping or dragging any of the bricks.

33 |

Example

34 |
35 |
36 |
37 | × 38 |
39 |
40 | × 41 |
42 |
43 | × 44 |
45 |
46 | × 47 |
48 |
49 | × 50 |
51 |
52 | × 53 |
54 |
55 | × 56 |
57 |
58 | × 59 |
60 |
61 | × 62 |
63 |
64 | × 65 |
66 |
67 | × 68 |
69 |
70 | × 71 |
72 |
73 | × 74 |
75 |
76 | × 77 |
78 |
79 | × 80 |
81 |
82 | × 83 |
84 |
85 | × 86 |
87 |
88 | × 89 |
90 |
91 | × 92 |
93 |
94 | × 95 |
96 |
97 |

98 | Add 99 |

100 |
101 |

Installation

102 |

To install download one of these packages and include the jquery.gridly.js and jquery.gridly.css files in your head with the following:

103 |
104 |
105 | 106 |
107 |
108 | 109 |
110 |
111 |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js" type="text/javascript"></script>
<script src="javascript/jquery.gridly.js" type="text/javascript"></script>
<link href="stylesheets/jquery.gridly.css" rel="stylesheet" type="text/css" />
112 |

Example

113 |

Setting up a gridly is easy. The following snippet is a good start:

114 |
<style type="text/css">
  .gridly {
    position: relative;
    width: 960px;
  }
  .brick.small {
    width: 140px;
    height: 140px;
  }
  .brick.large {
    width: 300px;
    height: 300px;
  }
</style>
<div class="gridly">
  <div class="brick small"></div>
  <div class="brick small"></div>
  <div class="brick large"></div>
  <div class="brick small"></div>
  <div class="brick small"></div>
  <div class="brick large"></div>
</div>
<script>
  $('.gridly').gridly({
    base: 60, // px 
    gutter: 20, // px
    columns: 12
  });
</script>
115 |

116 | Copyright (c) 2013 - 2015 117 | Kevin Sylvestre 118 |

119 | 124 |
125 | 126 | 127 | -------------------------------------------------------------------------------- /javascripts/jquery.gridly.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | jQuery Gridly 3 | Copyright 2020 Kevin Sylvestre 4 | 1.3.0 5 | ### 6 | 7 | "use strict" 8 | 9 | $ = jQuery 10 | 11 | class Animation 12 | @transitions: 13 | "webkitTransition": "webkitTransitionEnd" 14 | "mozTransition": "mozTransitionEnd" 15 | "oTransition": "oTransitionEnd" 16 | "transition": "transitionend" 17 | 18 | @transition: ($el) -> 19 | el = $el[0] 20 | return result for type, result of @transitions when el.style[type]? 21 | 22 | @execute: ($el, callback) -> 23 | transition = @transition($el) 24 | if transition? then $el.one(transition, callback) else callback() 25 | 26 | class Draggable 27 | 28 | constructor: ($container, selector, callbacks) -> 29 | @$container = $container 30 | @selector = selector 31 | @callbacks = callbacks 32 | @toggle() 33 | 34 | bind: (method = 'on') => 35 | $(document)[method] 'mousemove touchmove', @moved 36 | $(document)[method] 'mouseup touchcancel', @ended 37 | 38 | toggle: (method = 'on') => 39 | @$container[method] 'mousedown touchstart', @selector, @began 40 | @$container[method] 'touchend', @selector, @touchend 41 | @$container[method] 'click', @selector, @click 42 | 43 | on: => 44 | @toggle('on') 45 | 46 | off: => 47 | @toggle('off') 48 | 49 | coordinate: (event) => 50 | switch event.type 51 | when 'touchstart','touchmove','touchend','touchcancel' then event.originalEvent.touches[0] 52 | else event 53 | 54 | began: (event) => 55 | return if @$target 56 | event.preventDefault() 57 | event.stopPropagation() 58 | @bind('on') 59 | 60 | @$target = $(event.target).closest(@$container.find(@selector)) 61 | @$target.addClass('dragging') 62 | 63 | @origin = 64 | x: @coordinate(event).pageX - @$target.position().left 65 | y: @coordinate(event).pageY - @$target.position().top 66 | 67 | @callbacks?.began?(event) 68 | 69 | ended: (event) => 70 | return unless @$target? 71 | if event.type != 'touchend' 72 | event.preventDefault() 73 | event.stopPropagation() 74 | @bind('off') 75 | 76 | @$target.removeClass('dragging') 77 | 78 | delete @$target 79 | delete @origin 80 | 81 | @callbacks?.ended?(event) 82 | 83 | moved: (event) => 84 | return unless @$target? 85 | event.preventDefault() 86 | event.stopPropagation() 87 | 88 | @$target.css 89 | left: @coordinate(event).pageX - @origin.x 90 | top: @coordinate(event).pageY - @origin.y 91 | 92 | @dragged = @$target 93 | @callbacks?.moved?(event) 94 | 95 | click: (event) => 96 | return unless @dragged 97 | event.preventDefault() 98 | event.stopPropagation() 99 | delete @dragged 100 | 101 | touchend: (event) => 102 | @ended(event) 103 | @click(event) 104 | 105 | class Gridly 106 | 107 | @settings: 108 | base: 60 109 | gutter: 20 110 | columns: 12 111 | draggable: 112 | zIndex: 800 113 | selector : '> *' 114 | 115 | @gridly: ($el, options = {}) -> 116 | data = $el.data('_gridly') 117 | if data 118 | $.extend data.settings, options 119 | else 120 | data = new Gridly($el, options) 121 | $el.data('_gridly', data) 122 | return data 123 | 124 | constructor: ($el, settings = {}) -> 125 | @$el = $el 126 | @settings = $.extend {}, Gridly.settings, settings 127 | @ordinalize(@$('> *')) 128 | @draggable() unless @settings.draggable is false 129 | return @ 130 | 131 | ordinalize: ($elements) => 132 | for i in [0 .. $elements.length] 133 | $element = $($elements[i]) 134 | $element.data('position', i) 135 | 136 | reordinalize: ($element, position) => 137 | $element.data('position', position) 138 | 139 | $: (selector) => 140 | @$el.find(selector) 141 | 142 | compare: (d, s) => 143 | return +1 if d.y > s.y + s.h 144 | return -1 if s.y > d.y + d.h 145 | return +1 if (d.x + (d.w / 2)) > (s.x + (s.w / 2)) 146 | return -1 if (s.x + (s.w / 2)) > (d.x + (d.w / 2)) 147 | return 0 148 | 149 | draggable: (method) => 150 | @_draggable ?= new Draggable @$el, @settings.draggable.selector, 151 | began: @draggingBegan 152 | ended: @draggingEnded 153 | moved: @draggingMoved 154 | @_draggable[method]() if method? 155 | 156 | $sorted: ($elements) => 157 | ($elements || @$('> *')).sort (a,b) -> 158 | $a = $(a) 159 | $b = $(b) 160 | aPosition = $a.data('position') 161 | bPosition = $b.data('position') 162 | aPositionInt = parseInt(aPosition) 163 | bPositionInt = parseInt(bPosition) 164 | return -1 if aPosition? and not bPosition? 165 | return +1 if bPosition? and not aPosition? 166 | return -1 if not aPosition and not bPosition and $a.index() < $b.index() 167 | return +1 if not bPosition and not aPosition and $b.index() < $a.index() 168 | return -1 if aPositionInt < bPositionInt 169 | return +1 if bPositionInt < aPositionInt 170 | return 0 171 | 172 | draggingBegan: (event) => 173 | $elements = @$sorted() 174 | @ordinalize($elements) 175 | setTimeout @layout, 0 176 | @settings?.callbacks?.reordering?($elements) 177 | 178 | draggingEnded: (event) => 179 | $elements = @$sorted() 180 | @ordinalize($elements) 181 | setTimeout @layout, 0 182 | @settings?.callbacks?.reordered?($elements, @_draggable.dragged) 183 | 184 | draggingMoved: (event) => 185 | $dragging = $(event.target).closest(@$(@settings.draggable.selector)) 186 | $elements = @$sorted(@$(@settings.draggable.selector)) 187 | positions = @structure($elements).positions 188 | original = index = $dragging.data('position') 189 | 190 | for element in positions.filter((position) -> position.$element.is($dragging)) 191 | element.x = $dragging.position().left 192 | element.y = $dragging.position().top 193 | element.w = $dragging.data('width') || $dragging.outerWidth() 194 | element.h = $dragging.data('height') || $dragging.outerHeight() 195 | 196 | positions.sort @compare 197 | 198 | $elements = positions.map (position) -> position.$element 199 | $elements = (@settings.callbacks?.optimize || @optimize)($elements) 200 | 201 | for i in [0...$elements.length] 202 | @reordinalize($($elements[i]), i) 203 | 204 | @layout() 205 | 206 | size: ($element) => 207 | (($element.data('width') || $element.outerWidth()) + @settings.gutter) / (@settings.base + @settings.gutter) 208 | 209 | position: ($element, columns) => 210 | size = @size($element) 211 | 212 | height = Infinity 213 | column = 0 214 | 215 | for i in [0 ... (columns.length - size)] 216 | max = Math.max columns[i ... (i + size)]... 217 | if max < height 218 | height = max 219 | column = i 220 | 221 | for i in [column ... column + size] 222 | columns[i] = height + ($element.data('height') || $element.outerHeight()) + @settings.gutter 223 | 224 | x: (column * (@settings.base + @settings.gutter)) 225 | y: height 226 | 227 | structure: ($elements = @$sorted()) => 228 | positions = [] 229 | columns = (0 for i in [0 .. @settings.columns]) 230 | 231 | for index in [0 ... $elements.length] 232 | $element = $($elements[index]) 233 | 234 | position = @position($element, columns) 235 | positions.push 236 | x: position.x 237 | y: position.y 238 | w: $element.data('width') || $element.outerWidth() 239 | h: $element.data('height') || $element.outerHeight() 240 | $element: $element 241 | 242 | height: Math.max columns... 243 | positions: positions 244 | 245 | layout: => 246 | $elements = (@settings.callbacks?.optimize || @optimize)(@$sorted()) 247 | 248 | structure = @structure($elements) 249 | 250 | for index in [0 ... $elements.length] 251 | $element = $($elements[index]) 252 | position = structure.positions[index] 253 | 254 | continue if $element.is('.dragging') 255 | 256 | $element.css 257 | position: 'absolute' 258 | left: position.x 259 | top: position.y 260 | 261 | @$el.css 262 | height: structure.height 263 | 264 | optimize: (originals) => 265 | results = [] 266 | 267 | columns = 0 268 | while originals.length > 0 269 | columns = 0 if columns is @settings.columns 270 | 271 | index = 0 272 | for index in [0...originals.length] 273 | break unless columns + @size($(originals[index])) > @settings.columns 274 | 275 | if index is originals.length 276 | index = 0 277 | columns = 0 278 | 279 | columns += @size($(originals[index])) 280 | 281 | # Move from originals into results 282 | results.push(originals.splice(index,1)[0]) 283 | 284 | return results 285 | 286 | $.fn.extend 287 | gridly: (option = {}, parameters...) -> 288 | @each -> 289 | $this = $(@) 290 | 291 | options = $.extend {}, $.fn.gridly.defaults, typeof option is "object" and option 292 | action = if typeof option is "string" then option else option.action 293 | action ?= "layout" 294 | 295 | Gridly.gridly($this, options)[action](parameters) 296 | -------------------------------------------------------------------------------- /javascripts/jquery.gridly.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 2.5.1 2 | (function() { 3 | /* 4 | jQuery Gridly 5 | Copyright 2020 Kevin Sylvestre 6 | 1.3.0 7 | */ 8 | "use strict"; 9 | var $, Animation, Draggable, Gridly; 10 | 11 | $ = jQuery; 12 | 13 | Animation = (function() { 14 | class Animation { 15 | static transition($el) { 16 | var el, ref, result, type; 17 | el = $el[0]; 18 | ref = this.transitions; 19 | for (type in ref) { 20 | result = ref[type]; 21 | if (el.style[type] != null) { 22 | return result; 23 | } 24 | } 25 | } 26 | 27 | static execute($el, callback) { 28 | var transition; 29 | transition = this.transition($el); 30 | if (transition != null) { 31 | return $el.one(transition, callback); 32 | } else { 33 | return callback(); 34 | } 35 | } 36 | 37 | }; 38 | 39 | Animation.transitions = { 40 | "webkitTransition": "webkitTransitionEnd", 41 | "mozTransition": "mozTransitionEnd", 42 | "oTransition": "oTransitionEnd", 43 | "transition": "transitionend" 44 | }; 45 | 46 | return Animation; 47 | 48 | }).call(this); 49 | 50 | Draggable = class Draggable { 51 | constructor($container, selector, callbacks) { 52 | this.bind = this.bind.bind(this); 53 | this.toggle = this.toggle.bind(this); 54 | this.on = this.on.bind(this); 55 | this.off = this.off.bind(this); 56 | this.coordinate = this.coordinate.bind(this); 57 | this.began = this.began.bind(this); 58 | this.ended = this.ended.bind(this); 59 | this.moved = this.moved.bind(this); 60 | this.click = this.click.bind(this); 61 | this.touchend = this.touchend.bind(this); 62 | this.$container = $container; 63 | this.selector = selector; 64 | this.callbacks = callbacks; 65 | this.toggle(); 66 | } 67 | 68 | bind(method = 'on') { 69 | $(document)[method]('mousemove touchmove', this.moved); 70 | return $(document)[method]('mouseup touchcancel', this.ended); 71 | } 72 | 73 | toggle(method = 'on') { 74 | this.$container[method]('mousedown touchstart', this.selector, this.began); 75 | this.$container[method]('touchend', this.selector, this.touchend); 76 | return this.$container[method]('click', this.selector, this.click); 77 | } 78 | 79 | on() { 80 | return this.toggle('on'); 81 | } 82 | 83 | off() { 84 | return this.toggle('off'); 85 | } 86 | 87 | coordinate(event) { 88 | switch (event.type) { 89 | case 'touchstart': 90 | case 'touchmove': 91 | case 'touchend': 92 | case 'touchcancel': 93 | return event.originalEvent.touches[0]; 94 | default: 95 | return event; 96 | } 97 | } 98 | 99 | began(event) { 100 | var ref; 101 | if (this.$target) { 102 | return; 103 | } 104 | event.preventDefault(); 105 | event.stopPropagation(); 106 | this.bind('on'); 107 | this.$target = $(event.target).closest(this.$container.find(this.selector)); 108 | this.$target.addClass('dragging'); 109 | this.origin = { 110 | x: this.coordinate(event).pageX - this.$target.position().left, 111 | y: this.coordinate(event).pageY - this.$target.position().top 112 | }; 113 | return (ref = this.callbacks) != null ? typeof ref.began === "function" ? ref.began(event) : void 0 : void 0; 114 | } 115 | 116 | ended(event) { 117 | var ref; 118 | if (this.$target == null) { 119 | return; 120 | } 121 | if (event.type !== 'touchend') { 122 | event.preventDefault(); 123 | event.stopPropagation(); 124 | } 125 | this.bind('off'); 126 | this.$target.removeClass('dragging'); 127 | delete this.$target; 128 | delete this.origin; 129 | return (ref = this.callbacks) != null ? typeof ref.ended === "function" ? ref.ended(event) : void 0 : void 0; 130 | } 131 | 132 | moved(event) { 133 | var ref; 134 | if (this.$target == null) { 135 | return; 136 | } 137 | event.preventDefault(); 138 | event.stopPropagation(); 139 | this.$target.css({ 140 | left: this.coordinate(event).pageX - this.origin.x, 141 | top: this.coordinate(event).pageY - this.origin.y 142 | }); 143 | this.dragged = this.$target; 144 | return (ref = this.callbacks) != null ? typeof ref.moved === "function" ? ref.moved(event) : void 0 : void 0; 145 | } 146 | 147 | click(event) { 148 | if (!this.dragged) { 149 | return; 150 | } 151 | event.preventDefault(); 152 | event.stopPropagation(); 153 | return delete this.dragged; 154 | } 155 | 156 | touchend(event) { 157 | this.ended(event); 158 | return this.click(event); 159 | } 160 | 161 | }; 162 | 163 | Gridly = (function() { 164 | class Gridly { 165 | static gridly($el, options = {}) { 166 | var data; 167 | data = $el.data('_gridly'); 168 | if (data) { 169 | $.extend(data.settings, options); 170 | } else { 171 | data = new Gridly($el, options); 172 | $el.data('_gridly', data); 173 | } 174 | return data; 175 | } 176 | 177 | constructor($el, settings = {}) { 178 | this.ordinalize = this.ordinalize.bind(this); 179 | this.reordinalize = this.reordinalize.bind(this); 180 | this.$ = this.$.bind(this); 181 | this.compare = this.compare.bind(this); 182 | this.draggable = this.draggable.bind(this); 183 | this.$sorted = this.$sorted.bind(this); 184 | this.draggingBegan = this.draggingBegan.bind(this); 185 | this.draggingEnded = this.draggingEnded.bind(this); 186 | this.draggingMoved = this.draggingMoved.bind(this); 187 | this.size = this.size.bind(this); 188 | this.position = this.position.bind(this); 189 | this.structure = this.structure.bind(this); 190 | this.layout = this.layout.bind(this); 191 | this.optimize = this.optimize.bind(this); 192 | this.$el = $el; 193 | this.settings = $.extend({}, Gridly.settings, settings); 194 | this.ordinalize(this.$('> *')); 195 | if (this.settings.draggable !== false) { 196 | this.draggable(); 197 | } 198 | return this; 199 | } 200 | 201 | ordinalize($elements) { 202 | var $element, i, j, ref, results1; 203 | results1 = []; 204 | for (i = j = 0, ref = $elements.length; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) { 205 | $element = $($elements[i]); 206 | results1.push($element.data('position', i)); 207 | } 208 | return results1; 209 | } 210 | 211 | reordinalize($element, position) { 212 | return $element.data('position', position); 213 | } 214 | 215 | $(selector) { 216 | return this.$el.find(selector); 217 | } 218 | 219 | compare(d, s) { 220 | if (d.y > s.y + s.h) { 221 | return +1; 222 | } 223 | if (s.y > d.y + d.h) { 224 | return -1; 225 | } 226 | if ((d.x + (d.w / 2)) > (s.x + (s.w / 2))) { 227 | return +1; 228 | } 229 | if ((s.x + (s.w / 2)) > (d.x + (d.w / 2))) { 230 | return -1; 231 | } 232 | return 0; 233 | } 234 | 235 | draggable(method) { 236 | if (this._draggable == null) { 237 | this._draggable = new Draggable(this.$el, this.settings.draggable.selector, { 238 | began: this.draggingBegan, 239 | ended: this.draggingEnded, 240 | moved: this.draggingMoved 241 | }); 242 | } 243 | if (method != null) { 244 | return this._draggable[method](); 245 | } 246 | } 247 | 248 | $sorted($elements) { 249 | return ($elements || this.$('> *')).sort(function(a, b) { 250 | var $a, $b, aPosition, aPositionInt, bPosition, bPositionInt; 251 | $a = $(a); 252 | $b = $(b); 253 | aPosition = $a.data('position'); 254 | bPosition = $b.data('position'); 255 | aPositionInt = parseInt(aPosition); 256 | bPositionInt = parseInt(bPosition); 257 | if ((aPosition != null) && (bPosition == null)) { 258 | return -1; 259 | } 260 | if ((bPosition != null) && (aPosition == null)) { 261 | return +1; 262 | } 263 | if (!aPosition && !bPosition && $a.index() < $b.index()) { 264 | return -1; 265 | } 266 | if (!bPosition && !aPosition && $b.index() < $a.index()) { 267 | return +1; 268 | } 269 | if (aPositionInt < bPositionInt) { 270 | return -1; 271 | } 272 | if (bPositionInt < aPositionInt) { 273 | return +1; 274 | } 275 | return 0; 276 | }); 277 | } 278 | 279 | draggingBegan(event) { 280 | var $elements, ref, ref1; 281 | $elements = this.$sorted(); 282 | this.ordinalize($elements); 283 | setTimeout(this.layout, 0); 284 | return (ref = this.settings) != null ? (ref1 = ref.callbacks) != null ? typeof ref1.reordering === "function" ? ref1.reordering($elements) : void 0 : void 0 : void 0; 285 | } 286 | 287 | draggingEnded(event) { 288 | var $elements, ref, ref1; 289 | $elements = this.$sorted(); 290 | this.ordinalize($elements); 291 | setTimeout(this.layout, 0); 292 | return (ref = this.settings) != null ? (ref1 = ref.callbacks) != null ? typeof ref1.reordered === "function" ? ref1.reordered($elements, this._draggable.dragged) : void 0 : void 0 : void 0; 293 | } 294 | 295 | draggingMoved(event) { 296 | var $dragging, $elements, element, i, index, j, k, len, original, positions, ref, ref1, ref2; 297 | $dragging = $(event.target).closest(this.$(this.settings.draggable.selector)); 298 | $elements = this.$sorted(this.$(this.settings.draggable.selector)); 299 | positions = this.structure($elements).positions; 300 | original = index = $dragging.data('position'); 301 | ref = positions.filter(function(position) { 302 | return position.$element.is($dragging); 303 | }); 304 | for (j = 0, len = ref.length; j < len; j++) { 305 | element = ref[j]; 306 | element.x = $dragging.position().left; 307 | element.y = $dragging.position().top; 308 | element.w = $dragging.data('width') || $dragging.outerWidth(); 309 | element.h = $dragging.data('height') || $dragging.outerHeight(); 310 | } 311 | positions.sort(this.compare); 312 | $elements = positions.map(function(position) { 313 | return position.$element; 314 | }); 315 | $elements = (((ref1 = this.settings.callbacks) != null ? ref1.optimize : void 0) || this.optimize)($elements); 316 | for (i = k = 0, ref2 = $elements.length; (0 <= ref2 ? k < ref2 : k > ref2); i = 0 <= ref2 ? ++k : --k) { 317 | this.reordinalize($($elements[i]), i); 318 | } 319 | return this.layout(); 320 | } 321 | 322 | size($element) { 323 | return (($element.data('width') || $element.outerWidth()) + this.settings.gutter) / (this.settings.base + this.settings.gutter); 324 | } 325 | 326 | position($element, columns) { 327 | var column, height, i, j, k, max, ref, ref1, ref2, size; 328 | size = this.size($element); 329 | height = 2e308; 330 | column = 0; 331 | for (i = j = 0, ref = columns.length - size; (0 <= ref ? j < ref : j > ref); i = 0 <= ref ? ++j : --j) { 332 | max = Math.max(...columns.slice(i, (i + size))); 333 | if (max < height) { 334 | height = max; 335 | column = i; 336 | } 337 | } 338 | for (i = k = ref1 = column, ref2 = column + size; (ref1 <= ref2 ? k < ref2 : k > ref2); i = ref1 <= ref2 ? ++k : --k) { 339 | columns[i] = height + ($element.data('height') || $element.outerHeight()) + this.settings.gutter; 340 | } 341 | return { 342 | x: column * (this.settings.base + this.settings.gutter), 343 | y: height 344 | }; 345 | } 346 | 347 | structure($elements = this.$sorted()) { 348 | var $element, columns, i, index, j, position, positions, ref; 349 | positions = []; 350 | columns = (function() { 351 | var j, ref, results1; 352 | results1 = []; 353 | for (i = j = 0, ref = this.settings.columns; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) { 354 | results1.push(0); 355 | } 356 | return results1; 357 | }).call(this); 358 | for (index = j = 0, ref = $elements.length; (0 <= ref ? j < ref : j > ref); index = 0 <= ref ? ++j : --j) { 359 | $element = $($elements[index]); 360 | position = this.position($element, columns); 361 | positions.push({ 362 | x: position.x, 363 | y: position.y, 364 | w: $element.data('width') || $element.outerWidth(), 365 | h: $element.data('height') || $element.outerHeight(), 366 | $element: $element 367 | }); 368 | } 369 | return { 370 | height: Math.max(...columns), 371 | positions: positions 372 | }; 373 | } 374 | 375 | layout() { 376 | var $element, $elements, index, j, position, ref, ref1, structure; 377 | $elements = (((ref = this.settings.callbacks) != null ? ref.optimize : void 0) || this.optimize)(this.$sorted()); 378 | structure = this.structure($elements); 379 | for (index = j = 0, ref1 = $elements.length; (0 <= ref1 ? j < ref1 : j > ref1); index = 0 <= ref1 ? ++j : --j) { 380 | $element = $($elements[index]); 381 | position = structure.positions[index]; 382 | if ($element.is('.dragging')) { 383 | continue; 384 | } 385 | $element.css({ 386 | position: 'absolute', 387 | left: position.x, 388 | top: position.y 389 | }); 390 | } 391 | return this.$el.css({ 392 | height: structure.height 393 | }); 394 | } 395 | 396 | optimize(originals) { 397 | var columns, index, j, ref, results; 398 | results = []; 399 | columns = 0; 400 | while (originals.length > 0) { 401 | if (columns === this.settings.columns) { 402 | columns = 0; 403 | } 404 | index = 0; 405 | for (index = j = 0, ref = originals.length; (0 <= ref ? j < ref : j > ref); index = 0 <= ref ? ++j : --j) { 406 | if (!(columns + this.size($(originals[index])) > this.settings.columns)) { 407 | break; 408 | } 409 | } 410 | if (index === originals.length) { 411 | index = 0; 412 | columns = 0; 413 | } 414 | columns += this.size($(originals[index])); 415 | // Move from originals into results 416 | results.push(originals.splice(index, 1)[0]); 417 | } 418 | return results; 419 | } 420 | 421 | }; 422 | 423 | Gridly.settings = { 424 | base: 60, 425 | gutter: 20, 426 | columns: 12, 427 | draggable: { 428 | zIndex: 800, 429 | selector: '> *' 430 | } 431 | }; 432 | 433 | return Gridly; 434 | 435 | }).call(this); 436 | 437 | $.fn.extend({ 438 | gridly: function(option = {}, ...parameters) { 439 | return this.each(function() { 440 | var $this, action, options; 441 | $this = $(this); 442 | options = $.extend({}, $.fn.gridly.defaults, typeof option === "object" && option); 443 | action = typeof option === "string" ? option : option.action; 444 | if (action == null) { 445 | action = "layout"; 446 | } 447 | return Gridly.gridly($this, options)[action](parameters); 448 | }); 449 | } 450 | }); 451 | 452 | }).call(this); 453 | -------------------------------------------------------------------------------- /javascripts/rainbow.js: -------------------------------------------------------------------------------- 1 | /* Rainbow v1.1.8 rainbowco.de | included languages: c, shell, java, coffeescript, generic, scheme, javascript, r, haskell, python, html, smalltalk, csharp, go, php, ruby, lua, css */ 2 | var m=!0; 3 | window.Rainbow=function(){function r(a){var b,c=a.getAttribute&&a.getAttribute("data-language")||0;if(!c){a=a.attributes;for(b=0;b=e[d][c])delete e[d][c],delete j[d][c];if(a>=c&&ac&&b'+b+""}function t(a,b,c,h){var f=a.exec(c);if(f){++u;!b.name&&"string"==typeof b.matches[0]&&(b.name=b.matches[0],delete b.matches[0]);var k=f[0],i=f.index,v=f[0].length+i,g=function(){function f(){t(a,b,c,h)}u%100>0?f():setTimeout(f,0)};if(D(i,v))g();else{var n=w(b.matches),l=function(a,c,h){if(a>=c.length)h(k);else{var d=f[c[a]];if(d){var e=b.matches[c[a]],i=e.language,g=e.name&&e.matches? 5 | e.matches:e,j=function(b,d,e){var i;i=0;var g;for(g=1;g/g,">").replace(/&(?![\w\#]+;)/g, 7 | "&"),b,c)}function p(a,b,c){if(b|<=|>=|zero\?|positive\?|negative\?|odd\?|even\?|max|min|\+|\-|\*|\/|abs|quotient|remainder|modulo|gcd|lcm|numerator|denominator|floor|ceiling|truncate|round|rationalize|exp|log|sin|cos|tan|asin|acos|atan|sqrt|expt|make\-rectangular|make\-polar|real\-part|imag\-part|magnitude|angle|exact\->inexact|inexact\->exact|number\->string|string\->number|not|boolean\?|pair\?|cons|car|cdr|set\-car!|set\-cdr!|caar|cadr|cdar|cddr|caaar|caadr|cadar|caddr|cdaar|cdadr|cddar|cdddr|caaaar|caaadr|caadar|caaddr|cadaar|cadadr|caddar|cadddr|cdaaar|cdaadr|cdadar|cdaddr|cddaar|cddadr|cdddar|cddddr|null\?|list\?|list|length|append|reverse|list\-tail|list\-ref|memq|memv|member|assq|assv|assoc|symbol\?|symbol\->string|string\->symbol|char\?|char=\?|char<\?|char>\?|char<=\?|char>=\?|char\-ci=\?|char\-ci<\?|char\-ci>\?|char\-ci<=\?|char\-ci>=\?|char\-alphabetic\?|char\-numeric\?|char\-whitespace\?|char\-upper\-case\?|char\-lower\-case\?|char\->integer|integer\->char|char\-upcase|char\-downcase|string\?|make\-string|string|string\-length|string\-ref|string\-set!|string=\?|string\-ci=\?|string<\?|string>\?|string<=\?|string>=\?|string\-ci<\?|string\-ci>\?|string\-ci<=\?|string\-ci>=\?|substring|string\-append|string\->list|list\->string|string\-copy|string\-fill!|vector\?|make\-vector|vector|vector\-length|vector\-ref|vector\-set!|vector\->list|list\->vector|vector\-fill!|procedure\?|apply|map|for\-each|force|call\-with\-current\-continuation|call\/cc|values|call\-with\-values|dynamic\-wind|eval|scheme\-report\-environment|null\-environment|interaction\-environment|call\-with\-input\-file|call\-with\-output\-file|input\-port\?|output\-port\?|current\-input\-port|current\-output\-port|with\-input\-from\-file|with\-output\-to\-file|open\-input\-file|open\-output\-file|close\-input\-port|close\-output\-port|read|read\-char|peek\-char|eof\-object\?|char\-ready\?|write|display|newline|write\-char|load|transcript\-on|transcript\-off)(?=[\]()\s#])/g}], 18 | m);Rainbow.extend("javascript",[{name:"selector",pattern:/(\s|^)\$(?=\.|\()/g},{name:"support",pattern:/\b(window|document)\b/g},{matches:{1:"support.property"},pattern:/\.(length|node(Name|Value))\b/g},{matches:{1:"support.function"},pattern:/(setTimeout|setInterval)(?=\()/g},{matches:{1:"support.method"},pattern:/\.(getAttribute|push|getElementById|getElementsByClassName|log|setTimeout|setInterval)(?=\()/g},{matches:{1:"support.tag.script",2:[{name:"string",pattern:/('|")(.*?)(\1)/g},{name:"entity.tag.script", 19 | pattern:/(\w+)/g}],3:"support.tag.script"},pattern:/(<\/?)(script.*?)(>)/g},{name:"string.regexp",matches:{1:"string.regexp.open",2:{name:"constant.regexp.escape",pattern:/\\(.){1}/g},3:"string.regexp.close",4:"string.regexp.modifier"},pattern:/(\/)(?!\*)(.+)(\/)([igm]{0,3})/g},{matches:{1:"storage",3:"entity.function"},pattern:/(var)?(\s|^)(.*)(?=\s?=\s?function\()/g},{matches:{1:"keyword",2:"entity.function"},pattern:/(new)\s+(.*)(?=\()/g},{name:"entity.function",pattern:/(\w+)(?=:\s{0,}function)/g}]);Rainbow.extend("r",[{matches:{1:{name:"keyword.operator",pattern:/\=|<\-|<-/g},2:{name:"string",matches:{name:"constant.character.escape",pattern:/\\('|"){1}/g}}},pattern:/(\(|\s|\[|\=|:)(('|")([^\\\1]|\\.)*?(\3))/gm},{matches:{1:"constant.language"},pattern:/\b(NULL|NA|TRUE|FALSE|T|F|NaN|Inf|NA_integer_|NA_real_|NA_complex_|NA_character_)\b/g},{matches:{1:"constant.symbol"},pattern:/[^0-9a-zA-Z\._](LETTERS|letters|month\.(abb|name)|pi)/g},{name:"keyword.operator",pattern:/<-|<-|-|==|<=|<=|>>|>=|<|>|&&|&&|&|&|!=|\|\|?|\*|\+|\^|\/|%%|%\/%|\=|%in%|%\*%|%o%|%x%|\$|:|~|\[{1,2}|\]{1,2}/g}, 20 | {matches:{1:"storage",3:"entity.function"},pattern:/(\s|^)(.*)(?=\s?=\s?function\s\()/g},{matches:{1:"storage.function"},pattern:/[^a-zA-Z0-9._](function)(?=\s*\()/g},{matches:{1:"namespace",2:"keyword.operator",3:"function.call"},pattern:/([a-zA-Z][a-zA-Z0-9._]+)([:]{2,3})([.a-zA-Z][a-zA-Z0-9._]*(?=\s*\())\b/g},{name:"support.function",pattern:/(^|[^0-9a-zA-Z\._])(array|character|complex|data\.frame|double|integer|list|logical|matrix|numeric|vector)(?=\s*\()/g}]);Rainbow.extend("haskell",[{name:"comment",pattern:/\{\-\-[\s\S(\w+)]+[\-\-][\}$]/gm},{name:"comment",pattern:/\-\-(.*)/g},{matches:{1:"keyword",2:"support.namespace"},pattern:/\b(module)\s(\w+)\s[\(]?(\w+)?[\)?]\swhere/g},{name:"keyword.operator",pattern:/\+|\!|\-|&(gt|lt|amp);|\/\=|\||\@|\:|\.|\+{2}|\:|\*|\=|#|\.{2}|(\\)[a-zA-Z_]/g},{name:"keyword",pattern:/\b(case|class|foreign|hiding|qualified|data|family|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|in|otherwise|module|newtype|of|then|type|where)\b/g}, 21 | {name:"keyword",pattern:/[\`][a-zA-Z_']*?[\`]/g},{matches:{1:"keyword",2:"keyword.operator"},pattern:/\b(infix|infixr|infixl)+\s\d+\s(\w+)*/g},{name:"entity.class",pattern:/\b([A-Z][A-Za-z0-9_']*)/g},{name:"meta.preprocessor",matches:{1:[{matches:{1:"keyword.define",2:"entity.name"},pattern:/(\w+)\s(\w+)\b/g},{name:"keyword.define",pattern:/endif/g},{name:"constant.numeric",pattern:/\d+/g},{matches:{1:"keyword.include",2:"string"},pattern:/(include)\s(.*?)$/g}]},pattern:/^\#([\S\s]*?)$/gm}]);Rainbow.extend("python",[{name:"variable.self",pattern:/self/g},{name:"constant.language",pattern:/None|True|False/g},{name:"support.object",pattern:/object/g},{name:"support.function.python",pattern:/\b(bs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|bin|file|iter|property|tuple|bool|filter|len|range|type|bytearray|float|list|raw_input|unichr|callable|format|locals|reduce|unicode|chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|__import__|complex|hash|min|set|apply|delattr|help|next|setattr|buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern)(?=\()/g}, 22 | {matches:{1:"keyword"},pattern:/\b(pass|lambda|with|is|not|in|from|elif)(?=\(|\b)/g},{matches:{1:"storage.class",2:"entity.name.class",3:"entity.other.inherited-class"},pattern:/(class)\s+(\w+)\((\w+?)\)/g},{matches:{1:"storage.function",2:"support.magic"},pattern:/(def)\s+(__\w+)(?=\()/g},{name:"support.magic",pattern:/__(name)__/g},{matches:{1:"keyword.control",2:"support.exception.type"},pattern:/(except) (\w+):/g},{matches:{1:"storage.function",2:"entity.name.function"},pattern:/(def)\s+(\w+)(?=\()/g}, 23 | {name:"entity.name.function.decorator",pattern:/@(\w+)/g},{name:"comment.docstring",pattern:/('{3}|"{3})[\s\S]*?\1/gm}]);Rainbow.extend("html",[{name:"source.php.embedded",matches:{2:{language:"php"}},pattern:/<\?=?(?!xml)(php)?([\s\S]*?)(\?>)/gm},{name:"source.css.embedded",matches:{"0":{language:"css"}},pattern:/<style(.*?)>([\s\S]*?)<\/style>/gm},{name:"source.js.embedded",matches:{"0":{language:"javascript"}},pattern:/<script(?! src)(.*?)>([\s\S]*?)<\/script>/gm},{name:"comment.html",pattern:/<\!--[\S\s]*?-->/g},{matches:{1:"support.tag.open",2:"support.tag.close"},pattern:/(<)|(\/?\??>)/g}, 24 | {name:"support.tag",matches:{1:"support.tag",2:"support.tag.special",3:"support.tag-name"},pattern:/(<\??)(\/|\!?)(\w+)/g},{matches:{1:"support.attribute"},pattern:/([a-z-]+)(?=\=)/gi},{matches:{1:"support.operator",2:"string.quote",3:"string.value",4:"string.quote"},pattern:/(=)('|")(.*?)(\2)/g},{matches:{1:"support.operator",2:"support.value"},pattern:/(=)([a-zA-Z\-0-9]*)\b/g},{matches:{1:"support.attribute"},pattern:/\s(\w+)(?=\s|>)(?![\s\S]*<)/g}],m);Rainbow.extend("smalltalk",[{name:"keyword.pseudovariable",pattern:/self|thisContext/g},{name:"keyword.constant",pattern:/false|nil|true/g},{name:"string",pattern:/'([^']|'')*'/g},{name:"string.symbol",pattern:/#\w+|#'([^']|'')*'/g},{name:"string.character",pattern:/\$\w+/g},{name:"comment",pattern:/"([^"]|"")*"/g},{name:"constant.numeric",pattern:/-?\d+(\.\d+)?((r-?|s)[A-Za-z0-9]+|e-?[0-9]+)?/g},{name:"entity.name.class",pattern:/\b[A-Z]\w*/g},{name:"entity.name.function",pattern:/\b[a-z]\w*:?/g}, 25 | {name:"entity.name.binary",pattern:/(<|>|&|[=~\|\\\/!@*\-_+])+/g},{name:"operator.delimiter",pattern:/;[\(\)\[\]\{\}]|#\[|#\(^\./g}],m);Rainbow.extend("csharp",[{name:"constant",pattern:/\b(false|null|true)\b/g},{name:"keyword",pattern:/\b(abstract|add|alias|ascending|as|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|descending|double|do|dynamic|else|enum|event|explicit|extern|false|finally|fixed|float|foreach|for|from|get|global|goto|group|if|implicit|int|interface|internal|into|in|is|join|let|lock|long|namespace|new|object|operator|orderby|out|override|params|partial|private|protected|public|readonly|ref|remove|return|sbyte|sealed|select|set|short|sizeof|stackalloc|static|string|struct|switch|this|throw|try|typeof|uint|unchecked|ulong|unsafe|ushort|using|value|var|virtual|void|volatile|where|while|yield)\b/g}, 26 | {matches:{1:"keyword",2:{name:"support.class",pattern:/\w+/g}},pattern:/(typeof)\s([^\$].*?)(\)|;)/g},{matches:{1:"keyword.namespace",2:{name:"support.namespace",pattern:/\w+/g}},pattern:/\b(namespace)\s(.*?);/g},{matches:{1:"storage.modifier",2:"storage.class",3:"entity.name.class",4:"storage.modifier.extends",5:"entity.other.inherited-class"},pattern:/\b(abstract|sealed)?\s?(class)\s(\w+)(\sextends\s)?([\w\\]*)?\s?\{?(\n|\})/g},{name:"keyword.static",pattern:/\b(static)\b/g},{matches:{1:"keyword.new", 27 | 2:{name:"support.class",pattern:/\w+/g}},pattern:/\b(new)\s([^\$].*?)(?=\)|\(|;|&)/g},{name:"string",pattern:/(")(.*?)\1/g},{name:"integer",pattern:/\b(0x[\da-f]+|\d+)\b/g},{name:"comment",pattern:/\/\*[\s\S]*?\*\/|(\/\/)[\s\S]*?$/gm},{name:"operator",pattern:/(\+\+|\+=|\+|--|-=|-|<<=|<<|<=|=>|>>=|>>|>=|!=|!|~|\^|\|\||&&|&=|&|\?\?|::|:|\*=|\*|\/=|%=|\|=|==|=)/g},{name:"preprocessor",pattern:/(\#if|\#else|\#elif|\#endif|\#define|\#undef|\#warning|\#error|\#line|\#region|\#endregion|\#pragma)[\s\S]*?$/gm}], 28 | m);Rainbow.extend("go",[{matches:{1:{name:"keyword.operator",pattern:/\=/g},2:{name:"string",matches:{name:"constant.character.escape",pattern:/\\(`|"){1}/g}}},pattern:/(\(|\s|\[|\=|:)((`|")([^\\\1]|\\.)*?(\3))/gm},{name:"comment",pattern:/\/\*[\s\S]*?\*\/|(\/\/)[\s\S]*?$/gm},{name:"constant.numeric",pattern:/\b(\d+(\.\d+)?(e(\+|\-)?\d+)?(f|d)?|0x[\da-f]+)\b/gi},{matches:{1:"keyword"},pattern:/\b(break|c(ase|onst|ontinue)|d(efault|efer)|else|fallthrough|for|go(to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)(?=\(|\b)/gi}, 29 | {name:"constant.language",pattern:/true|false|null|string|byte|rune|u?int(8|16|32|64)?|float(32|64)|complex(64|128)/g},{name:"keyword.operator",pattern:/\+|\!|\-|&(gt|lt|amp);|\||\*|\:?=/g},{matches:{1:"function.call"},pattern:/(\w+?)(?=\()/g},{matches:{1:"storage.function",2:"entity.name.function"},pattern:/(func)\s(.*?)(?=\()/g}]);Rainbow.extend("php",[{name:"support",pattern:/\becho\b/g},{matches:{1:"variable.dollar-sign",2:"variable"},pattern:/(\$)(\w+)\b/g},{name:"constant.language",pattern:/true|false|null/ig},{name:"constant",pattern:/\b[A-Z0-9_]{2,}\b/g},{name:"keyword.dot",pattern:/\./g},{name:"keyword",pattern:/\b(continue|break|die|end(for(each)?|switch|if)|case|require(_once)?|include(_once)?)(?=\(|\b)/g},{matches:{1:"keyword",2:{name:"support.class",pattern:/\w+/g}},pattern:/(instanceof)\s([^\$].*?)(\)|;)/g},{matches:{1:"support.function"}, 30 | pattern:/\b(array(_key_exists|_merge|_keys|_shift)?|isset|count|empty|unset|printf|is_(array|string|numeric|object)|sprintf|each|date|time|substr|pos|str(len|pos|tolower|_replace|totime)?|ord|trim|in_array|implode|end|preg_match|explode|fmod|define|link|list|get_class|serialize|file|sort|mail|dir|idate|log|intval|header|chr|function_exists|dirname|preg_replace|file_exists)(?=\()/g},{name:"variable.language.php-tag",pattern:/(<\?(php)?|\?>)/g},{matches:{1:"keyword.namespace",2:{name:"support.namespace", 31 | pattern:/\w+/g}},pattern:/\b(namespace|use)\s(.*?);/g},{matches:{1:"storage.modifier",2:"storage.class",3:"entity.name.class",4:"storage.modifier.extends",5:"entity.other.inherited-class",6:"storage.modifier.extends",7:"entity.other.inherited-class"},pattern:/\b(abstract|final)?\s?(class|interface|trait)\s(\w+)(\sextends\s)?([\w\\]*)?(\simplements\s)?([\w\\]*)?\s?\{?(\n|\})/g},{name:"keyword.static",pattern:/self::|static::/g},{matches:{1:"storage.function",2:"support.magic"},pattern:/(function)\s(__.*?)(?=\()/g}, 32 | {matches:{1:"keyword.new",2:{name:"support.class",pattern:/\w+/g}},pattern:/\b(new)\s([^\$].*?)(?=\)|\(|;)/g},{matches:{1:{name:"support.class",pattern:/\w+/g},2:"keyword.static"},pattern:/([\w\\]*?)(::)(?=\b|\$)/g},{matches:{2:{name:"support.class",pattern:/\w+/g}},pattern:/(\(|,\s?)([\w\\]*?)(?=\s\$)/g}]);Rainbow.extend("ruby",[{name:"string",matches:{1:"string.open",2:{name:"string.keyword",pattern:/(\#\{.*?\})/g},3:"string.close"},pattern:/("|`)(.*?[^\\\1])?(\1)/g},{name:"string",pattern:/('|"|`)([^\\\1\n]|\\.)*\1/g},{name:"string",pattern:/%[qQ](?=(\(|\[|\{|<|.)(.*?)(?:'|\)|\]|\}|>|\1))(?:\(\2\)|\[\2\]|\{\2\}|\<\2>|\1\2\1)/g},{matches:{1:"string",2:"string",3:"string"},pattern:/(<<)(\w+).*?$([\s\S]*?^\2)/gm},{matches:{1:"string",2:"string",3:"string"},pattern:/(<<\-)(\w+).*?$([\s\S]*?\2)/gm}, 33 | {name:"string.regexp",matches:{1:"string.regexp",2:{name:"string.regexp",pattern:/\\(.){1}/g},3:"string.regexp",4:"string.regexp"},pattern:/(\/)(.*?)(\/)([a-z]*)/g},{name:"string.regexp",matches:{1:"string.regexp",2:{name:"string.regexp",pattern:/\\(.){1}/g},3:"string.regexp",4:"string.regexp"},pattern:/%r(?=(\(|\[|\{|<|.)(.*?)('|\)|\]|\}|>|\1))(?:\(\2\)|\[\2\]|\{\2\}|\<\2>|\1\2\1)([a-z]*)/g},{name:"comment",pattern:/#.*$/gm},{name:"comment",pattern:/^\=begin[\s\S]*?\=end$/gm},{matches:{1:"constant"}, 34 | pattern:/(\w+:)[^:]/g},{matches:{1:"constant.symbol"},pattern:/[^:](:(?:\w+|(?=['"](.*?)['"])(?:"\2"|'\2')))/g},{name:"constant.numeric",pattern:/\b(0x[\da-f]+|\d+)\b/g},{name:"support.class",pattern:/\b[A-Z]\w*(?=((\.|::)[A-Za-z]|\[))/g},{name:"constant",pattern:/\b[A-Z]\w*\b/g},{matches:{1:"storage.class",2:"entity.name.class",3:"entity.other.inherited-class"},pattern:/\s*(class)\s+((?:(?:::)?[A-Z]\w*)+)(?:\s+<\s+((?:(?:::)?[A-Z]\w*)+))?/g},{matches:{1:"storage.module",2:"entity.name.class"}, 35 | pattern:/\s*(module)\s+((?:(?:::)?[A-Z]\w*)+)/g},{name:"variable.global",pattern:/\$([a-zA-Z_]\w*)\b/g},{name:"variable.class",pattern:/@@([a-zA-Z_]\w*)\b/g},{name:"variable.instance",pattern:/@([a-zA-Z_]\w*)\b/g},{matches:{1:"keyword.control"},pattern:/[^\.]\b(BEGIN|begin|case|class|do|else|elsif|END|end|ensure|for|if|in|module|rescue|then|unless|until|when|while)\b(?![?!])/g},{matches:{1:"keyword.control.pseudo-method"},pattern:/[^\.]\b(alias|alias_method|break|next|redo|retry|return|super|undef|yield)\b(?![?!])|\bdefined\?|\bblock_given\?/g}, 36 | {matches:{1:"constant.language"},pattern:/\b(nil|true|false)\b(?![?!])/g},{matches:{1:"variable.language"},pattern:/\b(__(FILE|LINE)__|self)\b(?![?!])/g},{matches:{1:"keyword.special-method"},pattern:/\b(require|gem|initialize|new|loop|include|extend|raise|attr_reader|attr_writer|attr_accessor|attr|catch|throw|private|module_function|public|protected)\b(?![?!])/g},{name:"keyword.operator",pattern:/\s\?\s|=|<<|<<=|%=|&=|\*=|\*\*=|\+=|\-=|\^=|\|{1,2}=|<<|<=>|<(?!<|=)|>(?!<|=|>)|<=|>=|===|==|=~|!=|!~|%|&|\*\*|\*|\+|\-|\/|\||~|>>/g}, 37 | {matches:{1:"keyword.operator.logical"},pattern:/[^\.]\b(and|not|or)\b/g},{matches:{1:"storage.function",2:"entity.name.function"},pattern:/(def)\s(.*?)(?=(\s|\())/g}],m);Rainbow.extend("lua",[{matches:{1:{name:"keyword.operator",pattern:/\=/g},2:{name:"string",matches:{name:"constant.character.escape",pattern:/\\('|"){1}/g}}},pattern:/(\(|\s|\[|\=)(('|")([^\\\1]|\\.)*?(\3))/gm},{name:"comment",pattern:/\-{2}\[{2}\-{2}[\s\S]*?\-{2}\]{2}\-{2}|(\-{2})[\s\S]*?$/gm},{name:"constant.numeric",pattern:/\b(\d+(\.\d+)?(e(\+|\-)?\d+)?(f|d)?|0x[\da-f]+)\b/gi},{matches:{1:"keyword"},pattern:/\b((a|e)nd|in|repeat|break|local|return|do|for|then|else(if)?|function|not|if|or|until|while)(?=\(|\b)/gi}, 38 | {name:"constant.language",pattern:/true|false|nil/g},{name:"keyword.operator",pattern:/\+|\!|\-|&(gt|lt|amp);|\||\*|\=|#|\.{2}/g},{matches:{1:"storage.function",2:"entity.name.function"},pattern:/(function)\s+(\w+[\:|\.]?\w+?)(?=\()/g},{matches:{1:"support.function"},pattern:/\b(print|require|module|\w+\.\w+)(?=\()/g}]);Rainbow.extend("css",[{name:"comment",pattern:/\/\*[\s\S]*?\*\//gm},{name:"constant.hex-color",pattern:/#([a-f0-9]{3}|[a-f0-9]{6})(?=;|\s)/gi},{matches:{1:"constant.numeric",2:"keyword.unit"},pattern:/(\d+)(px|em|cm|s|%)?/g},{name:"string",pattern:/('|")(.*?)\1/g},{name:"support.css-property",matches:{1:"support.vendor-prefix"},pattern:/(-o-|-moz-|-webkit-|-ms-)?[\w-]+(?=\s?:)(?!.*\{)/g},{matches:{1:[{name:"entity.name.sass",pattern:/&/g},{name:"direct-descendant",pattern:/>/g},{name:"entity.name.class", 39 | pattern:/\.[\w\-_]+/g},{name:"entity.name.id",pattern:/\#[\w\-_]+/g},{name:"entity.name.pseudo",pattern:/:[\w\-_]+/g},{name:"entity.name.tag",pattern:/\w+/g}]},pattern:/([\w\ ,:\.\#\&\;\-_]+)(?=.*\{)/g},{matches:{2:"support.vendor-prefix",3:"support.css-value"},pattern:/(:|,)\s?(-o-|-moz-|-webkit-|-ms-)?([a-zA-Z-]*)(?=\b)(?!.*\{)/g},{matches:{1:"support.tag.style",2:[{name:"string",pattern:/('|")(.*?)(\1)/g},{name:"entity.tag.style",pattern:/(\w+)/g}],3:"support.tag.style"},pattern:/(<\/?)(style.*?)(>)/g}], 40 | m); 41 | -------------------------------------------------------------------------------- /javascripts/sample.coffee: -------------------------------------------------------------------------------- 1 | $ -> 2 | 3 | brick = "
×
" 4 | 5 | $(document).on "click touchend", ".gridly .brick", (event) -> 6 | event.preventDefault() 7 | event.stopPropagation() 8 | $this = $(this) 9 | 10 | $this.toggleClass('small') 11 | $this.toggleClass('large') 12 | size = 140 if $this.hasClass('small') # HACK 13 | size = 300 if $this.hasClass('large') # HACK 14 | $this.data('width', size) 15 | $this.data('height', size) 16 | $('.gridly').gridly 'layout' 17 | 18 | $(document).on "click", ".gridly .delete", (event) -> 19 | event.preventDefault() 20 | event.stopPropagation() 21 | $this = $(this) 22 | 23 | $this.closest('.brick').remove() 24 | $('.gridly').gridly 'layout' 25 | 26 | $(document).on "click", ".add", (event) -> 27 | event.preventDefault() 28 | event.stopPropagation() 29 | $('.gridly').append(brick) 30 | $('.gridly').gridly() 31 | 32 | $('.gridly').gridly() 33 | -------------------------------------------------------------------------------- /javascripts/sample.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 2.5.1 2 | (function() { 3 | $(function() { 4 | var brick; 5 | brick = "
×
"; 6 | $(document).on("click touchend", ".gridly .brick", function(event) { 7 | var $this, size; 8 | event.preventDefault(); 9 | event.stopPropagation(); 10 | $this = $(this); 11 | $this.toggleClass('small'); 12 | $this.toggleClass('large'); 13 | if ($this.hasClass('small')) { // HACK 14 | size = 140; 15 | } 16 | if ($this.hasClass('large')) { // HACK 17 | size = 300; 18 | } 19 | $this.data('width', size); 20 | $this.data('height', size); 21 | return $('.gridly').gridly('layout'); 22 | }); 23 | $(document).on("click", ".gridly .delete", function(event) { 24 | var $this; 25 | event.preventDefault(); 26 | event.stopPropagation(); 27 | $this = $(this); 28 | $this.closest('.brick').remove(); 29 | return $('.gridly').gridly('layout'); 30 | }); 31 | $(document).on("click", ".add", function(event) { 32 | event.preventDefault(); 33 | event.stopPropagation(); 34 | $('.gridly').append(brick); 35 | return $('.gridly').gridly(); 36 | }); 37 | return $('.gridly').gridly(); 38 | }); 39 | 40 | }).call(this); 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery.gridly", 3 | "version": "1.3.0", 4 | "description": "Gridly is a jQuery plugin to enable dragging and dropping as well as resizing on a grid.", 5 | "main": "./javascripts/jquery.gridly.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/ksylvest/jquery-gridly.git" 9 | }, 10 | "author": "Kevin Sylvestre", 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/ksylvest/jquery-gridly/issues" 14 | }, 15 | "homepage": "https://github.com/ksylvest/jquery-gridly#readme" 16 | } 17 | -------------------------------------------------------------------------------- /packages/jquery.gridly.tar: -------------------------------------------------------------------------------- 1 | javascripts/jquery.gridly.js000644 000765 000024 00000033514 13677007261 017053 0ustar00kevinstaff000000 000000 // Generated by CoffeeScript 2.5.1 2 | (function() { 3 | /* 4 | jQuery Gridly 5 | Copyright 2020 Kevin Sylvestre 6 | 1.3.0 7 | */ 8 | "use strict"; 9 | var $, Animation, Draggable, Gridly; 10 | 11 | $ = jQuery; 12 | 13 | Animation = (function() { 14 | class Animation { 15 | static transition($el) { 16 | var el, ref, result, type; 17 | el = $el[0]; 18 | ref = this.transitions; 19 | for (type in ref) { 20 | result = ref[type]; 21 | if (el.style[type] != null) { 22 | return result; 23 | } 24 | } 25 | } 26 | 27 | static execute($el, callback) { 28 | var transition; 29 | transition = this.transition($el); 30 | if (transition != null) { 31 | return $el.one(transition, callback); 32 | } else { 33 | return callback(); 34 | } 35 | } 36 | 37 | }; 38 | 39 | Animation.transitions = { 40 | "webkitTransition": "webkitTransitionEnd", 41 | "mozTransition": "mozTransitionEnd", 42 | "oTransition": "oTransitionEnd", 43 | "transition": "transitionend" 44 | }; 45 | 46 | return Animation; 47 | 48 | }).call(this); 49 | 50 | Draggable = class Draggable { 51 | constructor($container, selector, callbacks) { 52 | this.bind = this.bind.bind(this); 53 | this.toggle = this.toggle.bind(this); 54 | this.on = this.on.bind(this); 55 | this.off = this.off.bind(this); 56 | this.coordinate = this.coordinate.bind(this); 57 | this.began = this.began.bind(this); 58 | this.ended = this.ended.bind(this); 59 | this.moved = this.moved.bind(this); 60 | this.click = this.click.bind(this); 61 | this.touchend = this.touchend.bind(this); 62 | this.$container = $container; 63 | this.selector = selector; 64 | this.callbacks = callbacks; 65 | this.toggle(); 66 | } 67 | 68 | bind(method = 'on') { 69 | $(document)[method]('mousemove touchmove', this.moved); 70 | return $(document)[method]('mouseup touchcancel', this.ended); 71 | } 72 | 73 | toggle(method = 'on') { 74 | this.$container[method]('mousedown touchstart', this.selector, this.began); 75 | this.$container[method]('touchend', this.selector, this.touchend); 76 | return this.$container[method]('click', this.selector, this.click); 77 | } 78 | 79 | on() { 80 | return this.toggle('on'); 81 | } 82 | 83 | off() { 84 | return this.toggle('off'); 85 | } 86 | 87 | coordinate(event) { 88 | switch (event.type) { 89 | case 'touchstart': 90 | case 'touchmove': 91 | case 'touchend': 92 | case 'touchcancel': 93 | return event.originalEvent.touches[0]; 94 | default: 95 | return event; 96 | } 97 | } 98 | 99 | began(event) { 100 | var ref; 101 | if (this.$target) { 102 | return; 103 | } 104 | event.preventDefault(); 105 | event.stopPropagation(); 106 | this.bind('on'); 107 | this.$target = $(event.target).closest(this.$container.find(this.selector)); 108 | this.$target.addClass('dragging'); 109 | this.origin = { 110 | x: this.coordinate(event).pageX - this.$target.position().left, 111 | y: this.coordinate(event).pageY - this.$target.position().top 112 | }; 113 | return (ref = this.callbacks) != null ? typeof ref.began === "function" ? ref.began(event) : void 0 : void 0; 114 | } 115 | 116 | ended(event) { 117 | var ref; 118 | if (this.$target == null) { 119 | return; 120 | } 121 | if (event.type !== 'touchend') { 122 | event.preventDefault(); 123 | event.stopPropagation(); 124 | } 125 | this.bind('off'); 126 | this.$target.removeClass('dragging'); 127 | delete this.$target; 128 | delete this.origin; 129 | return (ref = this.callbacks) != null ? typeof ref.ended === "function" ? ref.ended(event) : void 0 : void 0; 130 | } 131 | 132 | moved(event) { 133 | var ref; 134 | if (this.$target == null) { 135 | return; 136 | } 137 | event.preventDefault(); 138 | event.stopPropagation(); 139 | this.$target.css({ 140 | left: this.coordinate(event).pageX - this.origin.x, 141 | top: this.coordinate(event).pageY - this.origin.y 142 | }); 143 | this.dragged = this.$target; 144 | return (ref = this.callbacks) != null ? typeof ref.moved === "function" ? ref.moved(event) : void 0 : void 0; 145 | } 146 | 147 | click(event) { 148 | if (!this.dragged) { 149 | return; 150 | } 151 | event.preventDefault(); 152 | event.stopPropagation(); 153 | return delete this.dragged; 154 | } 155 | 156 | touchend(event) { 157 | this.ended(event); 158 | return this.click(event); 159 | } 160 | 161 | }; 162 | 163 | Gridly = (function() { 164 | class Gridly { 165 | static gridly($el, options = {}) { 166 | var data; 167 | data = $el.data('_gridly'); 168 | if (data) { 169 | $.extend(data.settings, options); 170 | } else { 171 | data = new Gridly($el, options); 172 | $el.data('_gridly', data); 173 | } 174 | return data; 175 | } 176 | 177 | constructor($el, settings = {}) { 178 | this.ordinalize = this.ordinalize.bind(this); 179 | this.reordinalize = this.reordinalize.bind(this); 180 | this.$ = this.$.bind(this); 181 | this.compare = this.compare.bind(this); 182 | this.draggable = this.draggable.bind(this); 183 | this.$sorted = this.$sorted.bind(this); 184 | this.draggingBegan = this.draggingBegan.bind(this); 185 | this.draggingEnded = this.draggingEnded.bind(this); 186 | this.draggingMoved = this.draggingMoved.bind(this); 187 | this.size = this.size.bind(this); 188 | this.position = this.position.bind(this); 189 | this.structure = this.structure.bind(this); 190 | this.layout = this.layout.bind(this); 191 | this.optimize = this.optimize.bind(this); 192 | this.$el = $el; 193 | this.settings = $.extend({}, Gridly.settings, settings); 194 | this.ordinalize(this.$('> *')); 195 | if (this.settings.draggable !== false) { 196 | this.draggable(); 197 | } 198 | return this; 199 | } 200 | 201 | ordinalize($elements) { 202 | var $element, i, j, ref, results1; 203 | results1 = []; 204 | for (i = j = 0, ref = $elements.length; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) { 205 | $element = $($elements[i]); 206 | results1.push($element.data('position', i)); 207 | } 208 | return results1; 209 | } 210 | 211 | reordinalize($element, position) { 212 | return $element.data('position', position); 213 | } 214 | 215 | $(selector) { 216 | return this.$el.find(selector); 217 | } 218 | 219 | compare(d, s) { 220 | if (d.y > s.y + s.h) { 221 | return +1; 222 | } 223 | if (s.y > d.y + d.h) { 224 | return -1; 225 | } 226 | if ((d.x + (d.w / 2)) > (s.x + (s.w / 2))) { 227 | return +1; 228 | } 229 | if ((s.x + (s.w / 2)) > (d.x + (d.w / 2))) { 230 | return -1; 231 | } 232 | return 0; 233 | } 234 | 235 | draggable(method) { 236 | if (this._draggable == null) { 237 | this._draggable = new Draggable(this.$el, this.settings.draggable.selector, { 238 | began: this.draggingBegan, 239 | ended: this.draggingEnded, 240 | moved: this.draggingMoved 241 | }); 242 | } 243 | if (method != null) { 244 | return this._draggable[method](); 245 | } 246 | } 247 | 248 | $sorted($elements) { 249 | return ($elements || this.$('> *')).sort(function(a, b) { 250 | var $a, $b, aPosition, aPositionInt, bPosition, bPositionInt; 251 | $a = $(a); 252 | $b = $(b); 253 | aPosition = $a.data('position'); 254 | bPosition = $b.data('position'); 255 | aPositionInt = parseInt(aPosition); 256 | bPositionInt = parseInt(bPosition); 257 | if ((aPosition != null) && (bPosition == null)) { 258 | return -1; 259 | } 260 | if ((bPosition != null) && (aPosition == null)) { 261 | return +1; 262 | } 263 | if (!aPosition && !bPosition && $a.index() < $b.index()) { 264 | return -1; 265 | } 266 | if (!bPosition && !aPosition && $b.index() < $a.index()) { 267 | return +1; 268 | } 269 | if (aPositionInt < bPositionInt) { 270 | return -1; 271 | } 272 | if (bPositionInt < aPositionInt) { 273 | return +1; 274 | } 275 | return 0; 276 | }); 277 | } 278 | 279 | draggingBegan(event) { 280 | var $elements, ref, ref1; 281 | $elements = this.$sorted(); 282 | this.ordinalize($elements); 283 | setTimeout(this.layout, 0); 284 | return (ref = this.settings) != null ? (ref1 = ref.callbacks) != null ? typeof ref1.reordering === "function" ? ref1.reordering($elements) : void 0 : void 0 : void 0; 285 | } 286 | 287 | draggingEnded(event) { 288 | var $elements, ref, ref1; 289 | $elements = this.$sorted(); 290 | this.ordinalize($elements); 291 | setTimeout(this.layout, 0); 292 | return (ref = this.settings) != null ? (ref1 = ref.callbacks) != null ? typeof ref1.reordered === "function" ? ref1.reordered($elements, this._draggable.dragged) : void 0 : void 0 : void 0; 293 | } 294 | 295 | draggingMoved(event) { 296 | var $dragging, $elements, element, i, index, j, k, len, original, positions, ref, ref1, ref2; 297 | $dragging = $(event.target).closest(this.$(this.settings.draggable.selector)); 298 | $elements = this.$sorted(this.$(this.settings.draggable.selector)); 299 | positions = this.structure($elements).positions; 300 | original = index = $dragging.data('position'); 301 | ref = positions.filter(function(position) { 302 | return position.$element.is($dragging); 303 | }); 304 | for (j = 0, len = ref.length; j < len; j++) { 305 | element = ref[j]; 306 | element.x = $dragging.position().left; 307 | element.y = $dragging.position().top; 308 | element.w = $dragging.data('width') || $dragging.outerWidth(); 309 | element.h = $dragging.data('height') || $dragging.outerHeight(); 310 | } 311 | positions.sort(this.compare); 312 | $elements = positions.map(function(position) { 313 | return position.$element; 314 | }); 315 | $elements = (((ref1 = this.settings.callbacks) != null ? ref1.optimize : void 0) || this.optimize)($elements); 316 | for (i = k = 0, ref2 = $elements.length; (0 <= ref2 ? k < ref2 : k > ref2); i = 0 <= ref2 ? ++k : --k) { 317 | this.reordinalize($($elements[i]), i); 318 | } 319 | return this.layout(); 320 | } 321 | 322 | size($element) { 323 | return (($element.data('width') || $element.outerWidth()) + this.settings.gutter) / (this.settings.base + this.settings.gutter); 324 | } 325 | 326 | position($element, columns) { 327 | var column, height, i, j, k, max, ref, ref1, ref2, size; 328 | size = this.size($element); 329 | height = 2e308; 330 | column = 0; 331 | for (i = j = 0, ref = columns.length - size; (0 <= ref ? j < ref : j > ref); i = 0 <= ref ? ++j : --j) { 332 | max = Math.max(...columns.slice(i, (i + size))); 333 | if (max < height) { 334 | height = max; 335 | column = i; 336 | } 337 | } 338 | for (i = k = ref1 = column, ref2 = column + size; (ref1 <= ref2 ? k < ref2 : k > ref2); i = ref1 <= ref2 ? ++k : --k) { 339 | columns[i] = height + ($element.data('height') || $element.outerHeight()) + this.settings.gutter; 340 | } 341 | return { 342 | x: column * (this.settings.base + this.settings.gutter), 343 | y: height 344 | }; 345 | } 346 | 347 | structure($elements = this.$sorted()) { 348 | var $element, columns, i, index, j, position, positions, ref; 349 | positions = []; 350 | columns = (function() { 351 | var j, ref, results1; 352 | results1 = []; 353 | for (i = j = 0, ref = this.settings.columns; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) { 354 | results1.push(0); 355 | } 356 | return results1; 357 | }).call(this); 358 | for (index = j = 0, ref = $elements.length; (0 <= ref ? j < ref : j > ref); index = 0 <= ref ? ++j : --j) { 359 | $element = $($elements[index]); 360 | position = this.position($element, columns); 361 | positions.push({ 362 | x: position.x, 363 | y: position.y, 364 | w: $element.data('width') || $element.outerWidth(), 365 | h: $element.data('height') || $element.outerHeight(), 366 | $element: $element 367 | }); 368 | } 369 | return { 370 | height: Math.max(...columns), 371 | positions: positions 372 | }; 373 | } 374 | 375 | layout() { 376 | var $element, $elements, index, j, position, ref, ref1, structure; 377 | $elements = (((ref = this.settings.callbacks) != null ? ref.optimize : void 0) || this.optimize)(this.$sorted()); 378 | structure = this.structure($elements); 379 | for (index = j = 0, ref1 = $elements.length; (0 <= ref1 ? j < ref1 : j > ref1); index = 0 <= ref1 ? ++j : --j) { 380 | $element = $($elements[index]); 381 | position = structure.positions[index]; 382 | if ($element.is('.dragging')) { 383 | continue; 384 | } 385 | $element.css({ 386 | position: 'absolute', 387 | left: position.x, 388 | top: position.y 389 | }); 390 | } 391 | return this.$el.css({ 392 | height: structure.height 393 | }); 394 | } 395 | 396 | optimize(originals) { 397 | var columns, index, j, ref, results; 398 | results = []; 399 | columns = 0; 400 | while (originals.length > 0) { 401 | if (columns === this.settings.columns) { 402 | columns = 0; 403 | } 404 | index = 0; 405 | for (index = j = 0, ref = originals.length; (0 <= ref ? j < ref : j > ref); index = 0 <= ref ? ++j : --j) { 406 | if (!(columns + this.size($(originals[index])) > this.settings.columns)) { 407 | break; 408 | } 409 | } 410 | if (index === originals.length) { 411 | index = 0; 412 | columns = 0; 413 | } 414 | columns += this.size($(originals[index])); 415 | // Move from originals into results 416 | results.push(originals.splice(index, 1)[0]); 417 | } 418 | return results; 419 | } 420 | 421 | }; 422 | 423 | Gridly.settings = { 424 | base: 60, 425 | gutter: 20, 426 | columns: 12, 427 | draggable: { 428 | zIndex: 800, 429 | selector: '> *' 430 | } 431 | }; 432 | 433 | return Gridly; 434 | 435 | }).call(this); 436 | 437 | $.fn.extend({ 438 | gridly: function(option = {}, ...parameters) { 439 | return this.each(function() { 440 | var $this, action, options; 441 | $this = $(this); 442 | options = $.extend({}, $.fn.gridly.defaults, typeof option === "object" && option); 443 | action = typeof option === "string" ? option : option.action; 444 | if (action == null) { 445 | action = "layout"; 446 | } 447 | return Gridly.gridly($this, options)[action](parameters); 448 | }); 449 | } 450 | }); 451 | 452 | }).call(this); 453 | stylesheets/jquery.gridly.css000644 000765 000024 00000000261 13677007120 017235 0ustar00kevinstaff000000 000000 /* jQuery Gridly 454 | * Copyright 2020 Kevin Sylvestre 455 | * 1.3.0 456 | */ 457 | .gridly, .gridly > :not(.dragging) { 458 | transition: all 0.4s ease-in-out; } 459 | .gridly .dragging { 460 | z-index: 800; } 461 | -------------------------------------------------------------------------------- /packages/jquery.gridly.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksylvest/jquery-gridly/65d1e4bfdc3f16cd837710d8b631b91c4db01ddc/packages/jquery.gridly.zip -------------------------------------------------------------------------------- /stylesheets/jquery.gridly.css: -------------------------------------------------------------------------------- 1 | /* jQuery Gridly 2 | * Copyright 2020 Kevin Sylvestre 3 | * 1.3.0 4 | */ 5 | .gridly, .gridly > :not(.dragging) { 6 | transition: all 0.4s ease-in-out; } 7 | .gridly .dragging { 8 | z-index: 800; } 9 | -------------------------------------------------------------------------------- /stylesheets/jquery.gridly.sass: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Gridly 3 | * Copyright 2020 Kevin Sylvestre 4 | * 1.3.0 5 | */ 6 | 7 | $black: #000 8 | $white: #FFF 9 | 10 | $namespace: "gridly" 11 | 12 | .#{$namespace} 13 | &, > :not(.dragging) 14 | transition: all 0.4s ease-in-out 15 | .dragging 16 | z-index: 800 17 | -------------------------------------------------------------------------------- /stylesheets/sample.css: -------------------------------------------------------------------------------- 1 | body, html, p, h1, h2, h3, h4, h5, h6 { 2 | font-family: "Lato", "Helvetica", serif; 3 | font-weight: normal; } 4 | 5 | code { 6 | font-family: "Consolas", "Monaco", monospace; 7 | font-weight: normal; } 8 | 9 | body, html, p, code { 10 | color: #888; } 11 | 12 | h1, h2, h3, h4, h5, h6 { 13 | color: #444; } 14 | 15 | pre { 16 | overflow: scroll; 17 | background: #EEE; 18 | padding: 10px; } 19 | 20 | .content { 21 | width: 980px; 22 | margin: 80px auto; } 23 | 24 | .formats .format { 25 | display: inline-block; } 26 | 27 | .zip { 28 | background: url("../images/zip.png"); 29 | display: block; 30 | width: 128px; 31 | height: 128px; } 32 | 33 | .tar { 34 | background: url("../images/tar.png"); 35 | display: block; 36 | width: 128px; 37 | height: 128px; } 38 | 39 | .fork { 40 | position: absolute; 41 | top: 0; 42 | left: 0; 43 | border: 0; } 44 | 45 | .button { 46 | display: block; 47 | padding: 20px; 48 | width: 200px; 49 | color: #FFF; 50 | background: #888; 51 | margin: 20px 0; 52 | text-align: center; 53 | text-decoration: none; 54 | border-radius: 4px; } 55 | 56 | pre .support.tag { 57 | color: #008; } 58 | pre .support.attribute { 59 | color: #800; } 60 | pre .string.value { 61 | color: #080; } 62 | 63 | .example { 64 | position: relative; } 65 | .example .brick { 66 | opacity: 1; 67 | cursor: pointer; 68 | position: relative; } 69 | .example .brick .delete { 70 | display: block; 71 | color: #FFF; 72 | background: rgba(255, 255, 255, 0.2); 73 | width: 40px; 74 | height: 40px; 75 | top: 0; 76 | right: 0; 77 | position: absolute; 78 | text-align: center; 79 | line-height: 40px; } 80 | .example .brick.small { 81 | width: 140px; 82 | height: 140px; } 83 | .example .brick.large { 84 | width: 300px; 85 | height: 300px; } 86 | .example .brick.dragging { 87 | opacity: 0.8; } 88 | .example .brick:nth-child(20n + 1) { 89 | background: #1ABC9C; } 90 | .example .brick:nth-child(20n + 2) { 91 | background: #16A085; } 92 | .example .brick:nth-child(20n + 3) { 93 | background: #2ECC71; } 94 | .example .brick:nth-child(20n + 4) { 95 | background: #27AE60; } 96 | .example .brick:nth-child(20n + 5) { 97 | background: #3498DB; } 98 | .example .brick:nth-child(20n + 6) { 99 | background: #2980B9; } 100 | .example .brick:nth-child(20n + 7) { 101 | background: #9B59B6; } 102 | .example .brick:nth-child(20n + 8) { 103 | background: #8E44AD; } 104 | .example .brick:nth-child(20n + 9) { 105 | background: #34495E; } 106 | .example .brick:nth-child(20n + 10) { 107 | background: #2C3E50; } 108 | .example .brick:nth-child(20n + 11) { 109 | background: #F1C40F; } 110 | .example .brick:nth-child(20n + 12) { 111 | background: #F39C12; } 112 | .example .brick:nth-child(20n + 13) { 113 | background: #E67E22; } 114 | .example .brick:nth-child(20n + 14) { 115 | background: #D35400; } 116 | .example .brick:nth-child(20n + 15) { 117 | background: #E74C3C; } 118 | .example .brick:nth-child(20n + 16) { 119 | background: #C0392B; } 120 | .example .brick:nth-child(20n + 17) { 121 | background: #ECF0F1; } 122 | .example .brick:nth-child(20n + 18) { 123 | background: #BDC3C7; } 124 | .example .brick:nth-child(20n + 19) { 125 | background: #95A5A6; } 126 | .example .brick:nth-child(20n + 20) { 127 | background: #7F8C8D; } 128 | -------------------------------------------------------------------------------- /stylesheets/sample.sass: -------------------------------------------------------------------------------- 1 | $colors: #1ABC9C, #16A085, #2ECC71, #27AE60, #3498DB, #2980B9, #9B59B6, #8E44AD, #34495E, #2C3E50, #F1C40F, #F39C12, #E67E22, #D35400, #E74C3C, #C0392B, #ECF0F1, #BDC3C7, #95A5A6, #7F8C8D 2 | 3 | body, html, p, h1, h2, h3, h4, h5, h6 4 | font-family: "Lato", "Helvetica", serif 5 | font-weight: normal 6 | 7 | code 8 | font-family: "Consolas", "Monaco", monospace 9 | font-weight: normal 10 | 11 | body, html, p, code 12 | color: #888 13 | 14 | h1, h2, h3, h4, h5, h6 15 | color: #444 16 | 17 | pre 18 | overflow: scroll 19 | background: #EEE 20 | padding: 10px 21 | 22 | .content 23 | width: 980px 24 | margin: 80px auto 25 | 26 | .formats 27 | .format 28 | display: inline-block 29 | 30 | .zip 31 | background: url('../images/zip.png') 32 | display: block 33 | width: 128px 34 | height: 128px 35 | 36 | .tar 37 | background: url('../images/tar.png') 38 | display: block 39 | width: 128px 40 | height: 128px 41 | 42 | .fork 43 | position: absolute 44 | top: 0 45 | left: 0 46 | border: 0 47 | 48 | .button 49 | display: block 50 | padding: 20px 51 | width: 200px 52 | color: #FFF 53 | background: #888 54 | margin: 20px 0 55 | text: 56 | align: center 57 | decoration: none 58 | border: 59 | radius: 4px 60 | 61 | pre 62 | .support 63 | &.tag 64 | color: #008 65 | &.attribute 66 | color: #800 67 | .string 68 | &.value 69 | color: #080 70 | 71 | .example 72 | position: relative 73 | .brick 74 | opacity: 1.0 75 | cursor: pointer 76 | position: relative 77 | .delete 78 | display: block 79 | color: #FFF 80 | background: rgba(#FFF, 0.2) 81 | width: 40px 82 | height: 40px 83 | top: 0 84 | right: 0 85 | position: absolute 86 | text-align: center 87 | line-height: 40px 88 | &.small 89 | width: 140px 90 | height: 140px 91 | &.large 92 | width: 300px 93 | height: 300px 94 | &.dragging 95 | opacity: 0.8 96 | $index: 0 97 | $length: length($colors) 98 | @each $color in $colors 99 | $index: $index + 1 100 | &:nth-child(#{$length}n + #{$index}) 101 | background: $color 102 | --------------------------------------------------------------------------------