This commit is contained in:
laf
2016-01-04 12:09:32 +00:00
316 changed files with 36603 additions and 11399 deletions

View File

@@ -4,4 +4,8 @@ gh-pages/
demo/
.idea
.DS_Store
.idea
*.iml
vendor
*.gem
*.css.map
demos/assets/css/demo.css

103
lib/gridster/.jshintrc Normal file
View File

@@ -0,0 +1,103 @@
{
// http://www.jshint.com/docs/
// Based on node-jshint@2.x.x
// ENFORCING OPTIONS
// These options tell JSHint to be more strict towards your code. Use them if
// you want to allow only a safe subset of JavaScript—very useful when your
// codebase is shared with a big number of developers with different skill
// levels.
"bitwise": true, //prohibits the use of bitwise operators such as ^ (XOR), | (OR) and others
"camelcase": false, //force all variable names to use either camelCase style or UPPER_CASE with underscores
"curly": true, //requires you to always put curly braces around blocks in loops and conditionals
"eqeqeq": true, //prohibits the use of == and != in favor of === and !==
"es3": false, //tells JSHint that your code needs to adhere to ECMAScript 3 specification
"forin": false, //requires all `for in` loops to filter object's items with `hasOwnProperty()`
"immed": true, //prohibits the use of immediate function invocations without wrapping them in parentheses
"indent": 2, //enforces specific tab width
"latedef": true, //prohibits the use of a variable before it was defined
"newcap": true, //requires you to capitalize names of constructor functions
"noarg": true, //prohibits the use of `arguments.caller` and `arguments.callee`
"noempty": true, //warns when you have an empty block in your code
"nonew": true, //prohibits the use of constructor functions for side-effects
"plusplus": false, //prohibits the use of unary increment and decrement operators
"quotmark": true, //enforces the consistency of quotation marks used throughout your code
"undef": true, //prohibits the use of explicitly undeclared variables
"unused": "vars", //warns when you define and never use your variables
"strict": true, //requires all functions to run in ECMAScript 5's strict mode
"trailing": true, //makes it an error to leave a trailing whitespace in your code
"maxparams": false, //set the max number of formal parameters allowed per function
"maxdepth": 6, //control how nested do you want your blocks to be
"maxstatements": false, //set the max number of statements allowed per function
"maxcomplexity": false, //control cyclomatic complexity throughout your code
// RELAXING OPTIONS
// These options allow you to suppress certain types of warnings. Use them
// only if you are absolutely positive that you know what you are doing.
"asi": false, //suppresses warnings about missing semicolons
"boss": false, //suppresses warnings about the use of assignments in cases where comparisons are expected
"debug": false, //suppresses warnings about the debugger statements in your code
"eqnull": false, //suppresses warnings about == null comparisons
"esnext": false, //your code uses ES.next specific features such as const
"evil": false, //suppresses warnings about the use of eval
"expr": true, //suppresses warnings about the use of expressions where normally you would expect to see assignments or function calls
"funcscope": false, //suppresses warnings about declaring variables inside of control structures while accessing them later from the outside
"globalstrict": false, //suppresses warnings about the use of global strict mode
"iterator": false, //suppresses warnings about the `__iterator__` property
"lastsemic": false, //suppresses warnings about missing semicolons, but only when the semicolon is omitted for the last statement in a one-line block
"laxbreak": false, //suppresses most of the warnings about possibly unsafe line breakings in your code
"laxcomma": false, //suppresses warnings about comma-first coding style
"loopfunc": false, //suppresses warnings about functions inside of loops
"moz": false, //tells JSHint that your code uses Mozilla JavaScript extensions
"multistr": false, //suppresses warnings about multi-line strings
"proto": false, //suppresses warnings about the `__proto__` property
"scripturl": false, //suppresses warnings about the use of script-targeted URLs—such as `javascript:...`
"smarttabs": false, //suppresses warnings about mixed tabs and spaces when the latter are used for alignmnent only
"shadow": false, //suppresses warnings about variable shadowing
"sub": false, //suppresses warnings about using `[]` notation when it can be expressed in dot notation
"supernew": false, //suppresses warnings about "weird" constructions like `new function () { ... }` and `new Object;`
"validthis": false, //suppresses warnings about possible strict violations when the code is running in strict mode and you use `this` in a non-constructor function
// ENVIRONMENTS
// These options pre-define global variables that are exposed by popular
// JavaScript libraries and runtime environments—such as browser or node.js.
// Essentially they are shortcuts for explicit declarations like
// /*global $:false, jQuery:false */
"browser": true, //defines globals exposed by modern browsers
"couch": false, //defines globals exposed by CouchDB
"devel": true, //defines globals that are usually used for logging poor-man's debugging: `console`, `alert`, etc.
"dojo": false, //defines globals exposed by the Dojo Toolkit
"jquery": true, //defines globals exposed by the jQuery JavaScript library
"mootools": false, //defines globals exposed by the MooTools JavaScript framework
"node": true, //defines globals available when your code is running inside of the Node runtime environment
"nonstandard": false, //defines non-standard but widely adopted globals such as `escape` and `unescape`
"phantom": false, //defines globals available when your core is running inside of the PhantomJS runtime environment
"qunit": true, //defines globals available when your core is running inside of the Qqunit runtime environment
"prototypejs": false, //defines globals exposed by the Prototype JavaScript framework
"rhino": false, //defines globals available when your code is running inside of the Rhino runtime environment
"worker": true, //defines globals available when your code is running inside of a Web Worker
"wsh": false, //defines globals available when your code is running as a script for the Windows Script Host
"yui": false, //defines globals exposed by the YUI JavaScript framework
"globals": {
"define": false,
"throttle": false,
"delay": false,
"debounce": false,
"jQuery": true,
"require": false,
"Gridster": false
},
// LEGACY
// These options are legacy from JSLint. Aside from bug fixes they will not
// be improved in any way and might be removed at any point.
"nomen": false, //disallows the use of dangling `_` in variables
"onevar": false, //allows only one `var` statement per function
"passfail": false, //makes JSHint stop on the first error or warning
"white": false //make JSHint check your source code against Douglas Crockford's JavaScript coding style
}

4
lib/gridster/.npmignore Normal file
View File

@@ -0,0 +1,4 @@
*
!README.md
!LICENSE
!dist/**/*

10
lib/gridster/.travis.yml Normal file
View File

@@ -0,0 +1,10 @@
language: node_js
node_js:
- "0.10"
install:
- npm install
- npm install -g bower grunt-cli
before_script:
- bower install
script:
- grunt build --verbose

View File

@@ -1,3 +1,105 @@
<a name="v0.6.10"></a>
### v0.6.10 (2015-05-31)
* Add Ruby on Rails support
<a name="v0.6.9"></a>
### v0.6.9 (2015-05-27)
* bug fixes for positions and overlap
* dist modified to support webpack deployements
* new 'sticky' layout option which allows widgets to be places absolutely into a position on the grid.
<a name="v0.6.8"></a>
### v0.6.8 (2015-04-28)
#### Bug Fixes
* **gridster:**
* responsive width now resizes based off wrapper not window ([e69c3e8f](http://github.com/dsmorse/gridster.js/commit/e69c3e8f64aa4557ef032e4d0d8185e83b1aed21))
* ensure coords instances are destroyed on widgets ([576b5ae3](http://github.com/dsmorse/gridster.js/commit/576b5ae3f0461b048d8ff9463509b860ffa8b194))
* `resize_widget` also accepts HTMLElements ([cda560f4](http://github.com/dsmorse/gridster.js/commit/cda560f4f3ca616d03d1e3230cd2ef4e69876d9c))
* changed "instanceof jQuery" to "instanceof $" ([c6226306](http://github.com/dsmorse/gridster.js/commit/c6226306c2ce9aa7d45d774d7de19088acba0c66))
* wrong addition solved in add_faux_rows/cols by adding parseInt ([d9471752](http://github.com/dsmorse/gridster.js/commit/d947175257d686801154a403016fd2ec7e6d40c2), closes [#426](http://github.com/dsmorse/gridster.js/issues/426), [#425](http://github.com/dsmorse/gridster.js/issues/425))
* preventing gridster from adding extra resize handles ([9d077da6](http://github.com/dsmorse/gridster.js/commit/9d077da676826606243c2552dc9997c492687203))
* destroy resize_api ([b1629326](http://github.com/dsmorse/gridster.js/commit/b16293268c6aa4be2ba0c8fb1b9806e590227606), closes [#473](http://github.com/dsmorse/gridster.js/issues/473))
* ensure widget dimensions and coords are always ints ([595a94f1](http://github.com/dsmorse/gridster.js/commit/595a94f1bdfaa4905ff51d9044e74105c81e6ff3))
#### Features
* **draggable:** autoscrolling ([d3f25f3f](http://github.com/dsmorse/gridster.js/commit/d3f25f3fbbcc738d8b3702d122533e64f37acd29))
* **gridster:**
* add config to set custom show/hide widget methods ([7de5bbab](http://github.com/dsmorse/gridster.js/commit/7de5bbabc0a01e8188a56881782dc74d6bf111d3))
* browserify compatibility ([43148b87](http://github.com/dsmorse/gridster.js/commit/43148b87e523352a7f9d01479c6fed3e87f46ba0))
* Common.js support ([446852a2](http://github.com/dsmorse/gridster.js/commit/446852a260aab2e7caf772a62fbde8b518c38816), closes [#434](http://github.com/dsmorse/gridster.js/issues/434))
* **gridster.css:** remove possible default pading ([2002c455](http://github.com/dsmorse/gridster.js/commit/2002c455957016cb441a317dbbb6e5f6662cb35a))
<a name="v0.6.7"></a>
### v0.6.7 (2015-04-16)
<a name="v0.6.6"></a>
### v0.6.6 (2015-04-08)
<a name="v0.6.5"></a>
### v0.6.5 (2015-04-06)
#### Bug Fixes
* **gridster:** fixed bugs in centering_widgets (widgets were getting smushed when being resized ([86053f8b](http://github.com/DecksterTeam/gridster.js/commit/86053f8be3d73a9db3d7eabc595324123dbcff13))
<a name="v0.6.4"></a>
### v0.6.4 (2015-03-19)
#### Bug Fixes
* **gridster:**
* added ability to center widgets in grid
<a name="v0.6.3"></a>
### v0.6.3 (2015-03-06)
#### Bug Fixes
* **gridster:**
* fixing resize limits when in fixed width mode feature(gridster): added fix_to_co ([6bb47dc1](http://github.com/DecksterTeam/gridster.js/commit/6bb47dc1ce36aef670b2acb7c244ec5f4ea440e0))
<a name="v0.6.2"></a>
### v0.6.2 (2015-02-23)
#### Bug Fixes
* **gridster:** forcing height of gridster container to auto when in collapsed mode ([749f37a5](http://github.com/DecksterTeam/gridster.js/commit/749f37a52074bd16362528f94ab28ec314379ee3))
<a name="v0.6.1"></a>
### v0.6.1 (2015-02-21)
#### Bug Fixes
* **gridster:**
* fixed expand_widget bug not expanding full width of window fix(gridster): user c ([dbc226d4](http://github.com/DecksterTeam/gridster.js/commit/dbc226d46c8224f753c07af6aff259785c60425f))
* fixing drag limit issues when using autogrow_cols ([afd83fea](http://github.com/DecksterTeam/gridster.js/commit/afd83fead8c719615ae01ef7b5d3863701ff2243))
* changed the way widgets were getting positioned so that margins are actually the ([a3913043](http://github.com/DecksterTeam/gridster.js/commit/a3913043579bae9f5ef28e34524ad7a8ae7dcafd))
<a name="v0.6.0"></a>
## v0.6.0 (2015-02-18)
#### Bug Fixes
* **gridster:** changed the way widgets were getting positioned so that margins are actually the ([a3913043](http://github.com/DecksterTeam/gridster.js/commit/a3913043579bae9f5ef28e34524ad7a8ae7dcafd))
#### Features
* **gridster:** make grid responsive ([a3913043](http://github.com/DecksterTeam/gridster.js/commit/a3913043579bae9f5ef28e34524ad7a8ae7dcafd))
<a name="v0.5.7"></a>
### v0.5.7 (2015-02-17)
<a name="v0.5.6"></a>
### v0.5.6 (2014-09-25)
@@ -183,3 +285,60 @@
* **gridster:** drag-and-drop widget resizing ([e1924053](http://github.com/ducksboard/gridster.js/commit/e19240532de0bad35ffe6e5fc63934819390adc5))
* **utils:** add delay helper to utils ([faa6c5db](http://github.com/ducksboard/gridster.js/commit/faa6c5db0002feccf681e9f919ed583eef152773))
dustmoo Modifications
===========
Changelog 2013-04-3
Fork now handles standard behavior properly with swap allowing larger widgets to shift down.
Changelog 2013-04-2
Added Demo to Repository.
Changelog 2013-02-27
Added "Static widget support" Static Items default to the "static" class.
You can customize this class by using the code below:
$.gridster({
static_class: 'custom_class',
draggable: {
items: ".gs_w:not(.custom_class)"
}
});
I have also added functions creating a much more thourough check of whether the player can occupy the space you are moving it too.
This version is much more reliable in swapping space with widgets.
There are also new options for Maximum Rows and Maximum Columns:
$.gridster({
max_rows: map_rows,
max_cols: map_cols,
shift_larger_widgets_down: false
});
Setting the maximum amount of rows only completely works if you disable shifting larger widgets down at the moment.
Changelog 11-26-2012
Reworked swapping functionality to better handle large to small widget handling.
---
Widgets of smaller or equal size to the dragged widget (player)
will swap places with the original widget.
This causes tiles to swap left and right as well as up and down.
By default smaller players will shift larger widgets down.
I have added an option to prevent this behavior:
$.gridster({
shift_larger_widgets_down: false
});
By setting shift_larger_widgets_down to false, smaller widgets will not displace larger ones.

View File

@@ -141,3 +141,60 @@ included in the project:
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
license your work under the same license as that used by the project.
#commit Message Guidelines
We use [automatic changelog creation](https://github.com/ajoslin/conventional-changelog), so it best if your commit messages follow the following conventions:
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on github as well as in various git tools.
### Type
Must be one of the following:
* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug or adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
### Scope
The scope could be anything specifying place of the commit change. For example `$location`,
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes"
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
**Breaking Changes** are detected as such if the Body contains a line starting with
`BREAKING CHANGES:` The rest of the commit message is then used for this.
A detailed explanation can be found in this [document](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/).

View File

@@ -1,183 +1,233 @@
/*global module:false*/
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
meta: {
banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
'<%= pkg.homepage ? "* " + pkg.homepage : "" %>\n' +
'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n\n',
'use strict';
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
meta: {
banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
'<%= pkg.homepage ? "* " + pkg.homepage : "" %>\n' +
'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n\n',
minibanner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> - ' +
'<%= pkg.homepage ? "* " + pkg.homepage + " - " : "" %>' +
'Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */ '
},
concat: {
options: {
stripBanners: true,
banner: '<%= meta.banner %>'
},
dist_js: {
src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js'],
dest: 'dist/jquery.<%= pkg.name %>.js'
},
minibanner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> - ' +
'<%= pkg.homepage ? "* " + pkg.homepage + " - " : "" %>' +
'Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */ '
},
concat: {
options: {
stripBanners: true,
banner: '<%= meta.banner %>'
},
dist_js: {
src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js'],
dest: 'dist/jquery.<%= pkg.name %>.js'
},
dist_extras_js: {
src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js', 'src/jquery.<%= pkg.name %>.extras.js'],
dest: 'dist/jquery.<%= pkg.name %>.with-extras.js'
},
dist_extras_js: {
src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js', 'src/jquery.<%= pkg.name %>.extras.js'],
dest: 'dist/jquery.<%= pkg.name %>.with-extras.js'
}
},
uglify: {
options: {
banner: '<%= meta.minibanner %>'
},
dist: {
files: {
'dist/jquery.<%= pkg.name %>.min.js': ['<%= concat.dist_js.dest %>']
}
},
dist_css: {
src: ['src/jquery.<%= pkg.name %>.css'],
dest: 'dist/jquery.<%= pkg.name %>.css'
},
dist_extras: {
files: {
'dist/jquery.<%= pkg.name %>.with-extras.min.js': ['<%= concat.dist_extras_js.dest %>']
}
}
},
cssmin: {
compress: {
options: {
keepSpecialComments: 0,
banner: '<%= meta.minibanner %>'
},
files: {
'dist/jquery.<%= pkg.name %>.min.css': ['dist/jquery.<%= pkg.name %>.css']
}
}
},
jshint: {
options: {
verbose: true,
reporter: require('jshint-stylish'),
jshintrc: '.jshintrc'
},
files: ['GruntFile.js', 'src/**/*.js','sample/**/*.js', 'test/**/*.js']
},
yuidoc: {
compile: {
'name': 'gridster.js',
'description': 'gridster.js, a drag-and-drop multi-column jQuery grid plugin',
'version': 'v<%= pkg.version %>',
'url': 'http://gridster.net/',
'logo': 'https://ducksboard.com/static/images/svg/logo-ducksboard-black-small.svg',
options: {
paths: 'src/',
outdir: 'gh-pages/docs/'
}
}
},
replace: {
'rails-version': {
src: ['lib/gridster.js-rails/version.rb'],
dest: 'lib/gridster.js-rails/version.rb',
replacements: [{
from: /(\S*)(VERSION = ).*/g,
to: '$1$2"<%= pkg.version %>"'
}]
}
},
copy: {
dist: {
files: [{
expand: true,
dest: 'gh-pages/',
src: ['dist/*', 'demos/**']
},{
expand: true,
dest: 'dist',
src: ['src/jquery.gridster.less']
}]
},
rails: {
files: [{
expand: true,
flatten: true,
dest: 'vendor/assets/javascripts/',
src: ['dist/*.js']
}, {
expand: true,
flatten: true,
dest: 'vendor/assets/stylesheets/',
src: ['dist/*.css']
}]
}
},
shell: {
'build-rails-gem': {
command: 'gem build gridster.js-rails.gemspec'
},
'publish-rails-gem': {
command: 'gem push gridster.js-rails-<%= pkg.version %>.gem'
}
},
'gh-pages': {
target: {
options: {
message: 'update docs for changes from v<%= pkg.version %> ',
base: 'gh-pages',
add: true,
push: true
},
src: '**'
}
},
bump: {
options: {
files: ['package.json', 'bower.json'],
updateConfigs: ['pkg'],
commit: true,
commitMessage: 'Release v%VERSION%',
commitFiles: ['package.json', 'bower.json', 'CHANGELOG.md', 'dist/'], // '-a' for all files
createTag: true,
tagName: 'v%VERSION%',
tagMessage: 'Version %VERSION%',
push: false,
pushTo: 'origin',
gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' // options to use with '$ git describe'
}
},
clean: {
dist: [
'gridster.js-rails*.gem',
'.grunt',
'gh-pages',
'dist',
'vendor'
]
},
changelog: {
options: {
dest: 'CHANGELOG.md'
}
},
watch: {
files: ['libs/*.js', 'src/*.js', 'src/*.less', 'Gruntfile.js'],
tasks: ['concat', 'uglify', 'less', 'cssmin']
},
qunit: {
files: [
'test/jquery.gridster.html'
]
},
less: {
default: {
options: {
sourceMap: true,
sourceMapFilename: 'dist/jquery.gridster.css.map'
},
files: {
'dist/jquery.gridster.css': 'src/jquery.gridster.less'
}
},
demo: {
options: {
sourceMap: true,
sourceMapFilename: 'demos/assets/css/demo.css.map'
},
files: {
'demos/assets/css/demo.css': 'demos/assets/less/demo.less'
}
}
}
});
dist_demo_js: {
src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js'],
dest: 'gh-pages/dist/jquery.<%= pkg.name %>.js'
},
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
grunt.loadNpmTasks('grunt-bump');
grunt.loadNpmTasks('grunt-conventional-changelog');
grunt.loadNpmTasks('grunt-gh-pages');
grunt.loadNpmTasks('grunt-text-replace');
grunt.loadNpmTasks('grunt-shell');
dist_extras_demo_js: {
src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js', 'src/jquery.<%= pkg.name %>.extras.js'],
dest: 'gh-pages/dist/jquery.<%= pkg.name %>.with-extras.js'
},
// Default task.
grunt.registerTask('default', ['jshint', 'concat', 'less', 'uglify', 'cssmin', 'replace:rails-version', 'copy:rails']);
grunt.registerTask('build', ['default', 'qunit', 'shell:build-rails-gem']);
grunt.registerTask('test', ['jshint','qunit']);
grunt.registerTask('docs', ['clean', 'build', 'yuidoc', 'copy:dist', 'gh-pages']);
dist_demo_css: {
src: ['src/jquery.<%= pkg.name %>.css'],
dest: 'gh-pages/dist/jquery.<%= pkg.name %>.css'
}
},
uglify: {
options: {
banner: '<%= meta.minibanner %>'
},
dist: {
files: {
'dist/jquery.<%= pkg.name %>.min.js': ['<%= concat.dist_js.dest %>']
}
},
//builds and releases the gem files
grunt.registerTask('rails:publish', ['clean', 'build', 'shell:publish-rails-gem']);
dist_extras: {
files: {
'dist/jquery.<%= pkg.name %>.with-extras.min.js': ['<%= concat.dist_extras_js.dest %>']
}
},
//use one of the four release tasks to build the artifacts for the release (it will push the docs pages only)
grunt.registerTask('release:patch', ['build', 'bump-only:patch', 'build', 'docs', 'changelog']);
grunt.registerTask('release:minor', ['build', 'bump-only:minor', 'build', 'docs', 'changelog']);
grunt.registerTask('release:major', ['build', 'bump-only:major', 'build', 'docs', 'changelog']);
grunt.registerTask('release:git', ['build', 'bump-only:git', 'build', 'docs', 'changelog']);
dist_demo: {
files: {
'gh-pages/dist/jquery.<%= pkg.name %>.min.js': ['<%= concat.dist_js.dest %>'],
}
},
dist_extras_demo: {
files: {
'gh-pages/dist/jquery.<%= pkg.name %>.with-extras.min.js': ['<%= concat.dist_extras_js.dest %>']
}
}
},
cssmin: {
compress: {
options: {
keepSpecialComments: 0,
banner: '<%= meta.minibanner %>'
},
files: {
"dist/jquery.<%= pkg.name %>.min.css": ["dist/jquery.<%= pkg.name %>.css"],
"gh-pages/dist/jquery.<%= pkg.name %>.min.css": ["dist/jquery.<%= pkg.name %>.css"]
}
}
},
jshint: {
files: ['grunt.js', 'src/**/*.js', 'test/**/*.js']
},
watch: {
files: ['<%= lint.files %>', 'src/jquery.<%= pkg.name %>.css'],
tasks: 'min concat'
},
jshint: {
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: true,
newcap: true,
noarg: true,
sub: true,
undef: true,
boss: true,
eqnull: true,
browser: true
},
globals: {
jQuery: true
}
},
yuidoc: {
compile: {
"name": 'gridster.js',
"description": 'gridster.js, a drag-and-drop multi-column jQuery grid plugin',
"version": '0.1.0',
"url": 'http://gridster.net/',
"logo": 'https://ducksboard.com/static/images/svg/logo-ducksboard-black-small.svg',
options: {
paths: "src/",
outdir: "gh-pages/docs/"
}
}
},
bump: {
options: {
files: ['package.json'],
updateConfigs: ['pkg'],
commit: true,
commitMessage: 'Release v%VERSION%',
commitFiles: ['package.json', 'CHANGELOG.md', 'dist/'], // '-a' for all files
createTag: true,
tagName: 'v%VERSION%',
tagMessage: 'Version %VERSION%',
push: false,
pushTo: 'origin',
gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' // options to use with '$ git describe'
}
},
changelog: {
options: {
dest: 'CHANGELOG.md'
}
},
watch: {
files: ['libs/*.js', 'src/*.js', 'src/*.css', 'Gruntfile.js'],
tasks: ['concat', 'uglify', 'cssmin']
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-yuidoc');
grunt.loadNpmTasks('grunt-bump');
grunt.loadNpmTasks('grunt-conventional-changelog');
// Default task.
grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'cssmin']);
grunt.registerTask('build', ['default']);
grunt.registerTask('docs', ['yuidoc']);
grunt.registerTask('release', ['build', 'bump-only:patch', 'build', 'docs', 'changelog']);
grunt.registerTask('release:minor', ['build', 'bump-only:minor', 'build', 'docs', 'changelog']);
grunt.registerTask('release:major', ['build', 'bump-only:major', 'build', 'docs', 'changelog']);
grunt.registerTask('release:git', ['build', 'bump-only:git', 'build', 'docs', 'changelog', 'bump-commit']);
grunt.registerTask('release:commit', ['bump-commit']);
//use this task to publish the release artifacts
grunt.registerTask('release:commit', ['bump-commit', 'shell:publish-rails-gem']);
};

View File

@@ -1,35 +1,58 @@
[![Build Status](https://travis-ci.org/dsmorse/gridster.js.svg)](http://travis-ci.org/dsmorse/gridster.js)
[![GitHub version](https://badge.fury.io/gh/dsmorse%2Fgridster.js.svg)](http://dsmorse.github.io/gridster.js/)
[![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/)
[![Gem Version](https://badge.fury.io/rb/gridster.js-rails.svg)](https://rubygems.org/gems/gridster.js-rails)
[![Bower version](https://badge.fury.io/bo/gridster-js.svg)](http://bower.io/search/?q=gridster-js)
Gridster.js
===========
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ducksboard/gridster.js/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
Gridster is a jQuery plugin that makes building intuitive draggable
layouts from elements spanning multiple columns. You can even
dynamically add and remove elements from the grid.
More at [http://gridster.net/](http://gridster.net/).
[Releases](https://github.com/ducksboard/gridster.js/releases)
### Live Preview at: [http://dsmorse.github.io/gridster.js/](http://dsmorse.github.io/gridster.js/)
[CHANGELOG](https://github.com/ducksboard/gridster.js/blob/master/CHANGELOG.md)
[Releases](https://github.com/dsmorse/gridster.js/releases)
Gridster is maintained by Ducksboard occasionally but not actively.
@dustmoo and @pushmatrix have also write permissions as Gridster maintainers
they are. Thank you guys!
[CHANGELOG](https://github.com/dsmorse/gridster.js/blob/master/CHANGELOG.md)
Gridster was created by Ducksboard but they have basiclly abondoned the project
and even those who had write permissions to the repo are not merging pull requests.
## Forks
Mr @dustmoo (maintainer of Gridster) has his own fork of gridster.js
with some new interesting features like widget-swapping and static widgets.
As of result of the inactivity over the last year in the [Ducksboard](https://github.com/ducksboard/gridster.js) repository, [@dsmorse](https://github.com/dsmorse/gridster.js) has created a fork
for current support. He will GLADLY accept pull requests, and will be working to merge existing
Pull Requests from Ducksboard repo.
Can be found here: [dustmoo/gridster.js](https://github.com/dustmoo/gridster.js)
## Ruby on Rails integration
@dustmoo is working in his spare time to merge all these changes into
ducksboard/gridster.js
This artifact is published to [rubygems.org](https://rubygems.org/gems/gridster.js-rails) to be consumed by ruby on rails applications.
If anyone would like to help @dustmoo improve his fork and reconcile
it with the main library he would be happy for the help.
Include gridster.js-rails in Gemfile;
``` ruby
gem 'gridster.js-rails'
```
and run bundle install.
### Configuration
Add this line to app/assets/stylesheets/application.css
``` css
*= require jquery.gridster
```
Add this line to app/assets/javascripts/application.js
``` javascript
//= require jquery.gridster
```
## Contributing to this project

31
lib/gridster/bower.json Normal file
View File

@@ -0,0 +1,31 @@
{
"name": "gridster",
"homepage": "dsmorse.github.io/gridster.js/",
"version": "0.6.10",
"dependencies": {
"jquery": "^2.1.3"
},
"devDependencies": {
"requirejs": "^2.1.17",
"qunit": "~1.18.0"
},
"main": [
"dist/jquery.gridster.js",
"dist/jquery.gridster.css"
],
"private": false,
"ignore": [
".bowerrc",
".jshintrc",
".gitignore",
".travis.yml",
"CONTRIBUTING.md",
"Gruntfile.js",
"package.json",
"test/",
"gridster.js-rails.gemspec",
"Gemfile",
"Gemfile.lock",
"lib"
]
}

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Gridster Grid Swapping Demo</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var gridster = "";
$(document).ready(function () {
$(".gridster ul").gridster({
widget_margins: [10, 10],
widget_base_dimensions: [140, 140],
shift_larger_widgets_down: false
});
});
</script>
</head>
<body>
<style>
.gridster, .content {
width: 940px;
margin: 0 auto;
}
</style>
<div class="content">
<h1>Grid with larger widgets swapping spots with smaller ones</h1>
<p>This demo represents using the branch in swap mode. This works best with shift_larger_widgets_down set to "false". However, smaller widgets do
not displace larger ones.</p>
</div>
<div class="gridster">
<ul style="height: 480px; position: relative; ">
<li data-row="1" data-col="1" data-sizex="2" data-sizey="1" class="gs_w"></li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1" class="gs_w"></li>
<li data-row="3" data-col="2" data-sizex="2" data-sizey="1" class="gs_w"></li>
<li data-row="1" data-col="3" data-sizex="2" data-sizey="2" class="gs_w"></li>
<li class="try gs_w" data-row="1" data-col="5" data-sizex="1" data-sizey="1"></li>
<li data-row="2" data-col="1" data-sizex="2" data-sizey="1" class="gs_w"></li>
<li data-row="3" data-col="4" data-sizex="1" data-sizey="1" class="gs_w"></li>
<li data-row="1" data-col="6" data-sizex="1" data-sizey="1" class="gs_w"></li>
<li data-row="3" data-col="5" data-sizex="1" data-sizey="1" class="gs_w"></li>
<li data-row="2" data-col="5" data-sizex="1" data-sizey="1" class="gs_w"></li>
<li data-row="2" data-col="6" data-sizex="1" data-sizey="2" class="gs_w"></li>
</ul>
</div>
</body>
</html>

View File

@@ -0,0 +1,54 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Add widgets dynamically &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Add widgets dynamically</h1>
<p>Create a grid adding widgets from an Array (not from HTML) using <code>add_widget</code> method. Widget position (col, row) not specified.</p>
<div class="gridster">
<ul></ul>
</div>
<script type="text/javascript" id="code">
var gridster;
$(function () {
gridster = $(".gridster > ul").gridster({
widget_margins: [5, 5],
widget_base_dimensions: [100, 55]
}).data('gridster');
var widgets = [
['<li>0</li>', 1, 2],
['<li>1</li>', 3, 2],
['<li>2</li>', 3, 2],
['<li>3</li>', 2, 1],
['<li>4</li>', 4, 1],
['<li>5</li>', 1, 2],
['<li>6</li>', 2, 1],
['<li>7</li>', 3, 2],
['<li>8</li>', 1, 1],
['<li>9</li>', 2, 2],
['<li>10</li>', 1, 3]
];
$.each(widgets, function (i, widget) {
gridster.add_widget.apply(gridster, widget)
});
});
</script>
</body>
</html>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,25 @@
// Avoid `console` errors in browsers that lack a console.
(function () {
var method;
var noop = function () {
};
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});
while (length--) {
method = methods[length];
// Only stub undefined methods.
if (!console[method]) {
console[method] = noop;
}
}
}());
// Place any jQuery/helper plugins in here.

View File

@@ -0,0 +1,86 @@
/*! gridster.js - v0.6.10 - 2015-05-31
* https://dsmorse.github.io/gridster.js/
* Copyright (c) 2015 ducksboard; Licensed MIT */
@bg-color: #26941f;
body {
background: @bg-color;
font-size: 16px;
font-family: 'Helvetica Neue', Arial, sans-serif;
color: #ffffff;
margin: 0;
}
h1, h2, h3, p {
margin: 10px;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
.demo {
margin: 3em 0;
padding: 7.5em 0 5.5em;
background: @bg-color;
}
.demo:hover {
.gridster {
margin: 0 auto;
opacity: .8;
-webkit-transition: opacity .6s;
-moz-transition: opacity .6s;
-o-transition: opacity .6s;
-ms-transition: opacity .6s;
transition: opacity .6s;
}
}
.content {
color: white;
}
.gridster {
.gs-w {
background: #61A9CF;
cursor: pointer;
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}
.player {
-webkit-box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
background: #BBB;
}
.gs-w.try {
background-image: url(../img/sprite.png);
background-repeat: no-repeat;
background-position: 37px -169px;
}
.preview-holder {
border: none !important;
border-radius: 0 !important;
background: red !important;
}
ul {
background-color: #EFEFEF;
}
li {
font-size: 1em;
font-weight: bold;
text-align: center;
line-height: 100%;
}
}
ul {
list-style-type: none;
}
li {
list-style: none;
font-weight: bold;
}
.gridster-box {
position: relative;
width: 100%;
height: 100%;
}
.controls {
margin-bottom: 20px;
}

View File

@@ -0,0 +1,90 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Resize &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src=//cdnjs.cloudflare.com/ajax/libs/seedrandom/2.3.10/seedrandom.min.js></script>
<script src="../dist/jquery.gridster.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Resize</h1>
<p>As hommage to Netflix's <a href="https://github.com/Netflix/SimianArmy/wiki/Chaos-Monkey">Chaos Monkey</a>, this demo page is for testing. It attempts to insert a widget at a random location to ensure the overlap deconfliction locic works.</p>
<div class="controls">
<button class="js-fixed-random">Insert widget at random location</button>
<button class="js-random-random">Insert random sized widget at random location</button>
</div>
<div class="gridster">
<ul style="z-index: 2; float: left;position: absolute">
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
<li data-row="1" data-col="5" data-sizex="1" data-sizey="3">9</li>
</ul>
<svg width="100%" height="800px" xmlns="http://www.w3.org/2000/svg" style="float: left;
position: relative;
z-index: 5;
margin-top: 15px;">
<defs>
<pattern id="grid" width="105" height="105" patternUnits="userSpaceOnUse">
<rect width="105" height="105" fill="url(#smallGrid)"/>
<path d="M 105 0 L 0 0 0 105" fill="none" stroke="black" stroke-width="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
</svg>
</div>
<script type="text/javascript">
Math.seedrandom();
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
</script>
<script type="text/javascript">
var gridster;
var nextSimian = 10;
$(function () {
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 100],
avoid_overlapped_widgets: true,
widget_margins: [5, 5],
helper: 'clone',
resize: {
enabled: true
}
}).data('gridster');
$('.js-random-random').on('click', function () {
gridster.add_widget('<li>' + nextSimian + '</li>', getRandomInt(1, 5), getRandomInt(1, 5), getRandomInt(1, 15), getRandomInt(1, 15));
nextSimian++;
});
$('.js-fixed-random').on('click', function () {
gridster.add_widget('<li>' + nextSimian + '</li>', 1 , 1, getRandomInt(1, 15), getRandomInt(1, 15));
nextSimian++;
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,96 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Custom drag handle &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Custom drag handle</h1>
<p>Restricts dragging from starting unless the mousedown occurs on the specified element(s).</p>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">
<header>|||</header>
0
</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">
<header>|||</header>
1
</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">
<header>|||</header>
2
</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">
<header>|||</header>
3
</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">
<header>|||</header>
4
</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">
<header>|||</header>
5
</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">
<header>|||</header>
6
</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">
<header>|||</header>
7
</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">
<header>|||</header>
8
</li>
<li data-row="1" data-col="5" data-sizex="1" data-sizey="3">
<header>|||</header>
9
</li>
</ul>
</div>
<style type="text/css">
.gridster li header {
background: #999;
display: block;
font-size: 20px;
line-height: normal;
padding: 4px 0 6px;
margin-bottom: 20px;
cursor: move;
}
</style>
<script type="text/javascript">
var gridster;
$(function () {
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 120],
widget_margins: [5, 5],
draggable: {
handle: 'header'
}
}).data('gridster');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,52 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Dynamic grid width &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Dynamic grid width</h1>
<p>Drag or resize some widgets to the right side. Use <code>max_cols</code> option to set a maximum number of columns for the grid.</p>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
<li data-row="1" data-col="5" data-sizex="1" data-sizey="3">9</li>
</ul>
</div>
<script type="text/javascript">
var gridster;
$(function () {
var log = document.getElementById('log');
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 55],
widget_margins: [5, 5],
autogrow_cols: true,
resize: {
enabled: true
}
}).data('gridster');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Expandable widgets &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Expandable widgets</h1>
<p>Expand widgets when hover on them using <code>resize_widget</code> method.</p>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">0</li>
<li data-row="1" data-col="2" data-sizex="1" data-sizey="1">1</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="1">2</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">3</li>
<li data-row="2" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="2" data-col="2" data-sizex="1" data-sizey="1">5</li>
<li data-row="2" data-col="3" data-sizex="1" data-sizey="1">6</li>
<li data-row="2" data-col="4" data-sizex="1" data-sizey="1">7</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">8</li>
<li data-row="3" data-col="2" data-sizex="1" data-sizey="1">9</li>
<li data-row="3" data-col="3" data-sizex="1" data-sizey="1">10</li>
<li data-row="3" data-col="4" data-sizex="1" data-sizey="1">11</li>
</ul>
</div>
<script type="text/javascript">
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
</script>
<script type="text/javascript">
var gridster;
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 100],
widget_margins: [5, 5],
helper: 'clone'
}).data('gridster');
gridster.$el.ready(function () {
// resize widgets on hover
gridster.$el
.on('mouseenter', 'li', function () {
gridster.resize_widget($(this), 3, 3);
})
.on('mouseleave', 'li', function () {
gridster.resize_widget($(this), 1, 1);
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,63 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Grid from serialize &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Build grid from serialized positions</h1>
<p>Build a entire new grid from previously stored positions obtained with <code>serialize</code> method.</p>
<div class="controls">
<button class="js-seralize">Build from serialize</button>
</div>
<div class="gridster">
<ul>
</ul>
</div>
<script type="text/javascript">
var gridster;
// same object than generated with gridster.serialize() method
var serialization = [
{ col: 1, row: 1, size_x: 2, size_y: 2 },
{ col: 3, row: 1, size_x: 1, size_y: 2 },
{ col: 4, row: 1, size_x: 1, size_y: 1 },
{ col: 2, row: 3, size_x: 3, size_y: 1 },
{ col: 1, row: 4, size_x: 1, size_y: 1 },
{ col: 1, row: 3, size_x: 1, size_y: 1 },
{ col: 2, row: 4, size_x: 1, size_y: 1 },
{ col: 2, row: 5, size_x: 1, size_y: 1 }
];
// sort serialization
serialization = Gridster.sort_by_row_and_col_asc(serialization);
$(function () {
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 55],
widget_margins: [5, 5]
}).data('gridster');
$('.js-seralize').on('click', function () {
gridster.remove_all_widgets();
$.each(serialization, function () {
gridster.add_widget('<li />', this.size_x, this.size_y, this.col, this.row);
});
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<title>Gridster Demos</title>
<link rel="stylesheet" href="assets/css/demo.css">
</head>
<body>
<div class="content">
<h2>Samples</h2>
</div>
<ul>
<li><a href="adding-widgets-dynamically.html">Adding widgets dynamically</a></li>
<li><a href="custom-drag-handle.html">Custom drag handle</a></li>
<li><a href="expandable-widgets.html">Expandable widgets</a></li>
<li><a href="grid-from-serialize.html">Build grid from serialize</a></li>
<li><a href="multiple-grids.html">Multiple gridster instances on the same page</a></li>
<li><a href="resize.html">Resizable widgets</a></li>
<li><a href="chaosWidget.html">Chaos Widgets</a></li>
<li><a href="resize-limits.html">Resizable widgets with constraints</a></li>
<li><a href="serialize.html">Serialize widgets positions</a></li>
<li><a href="using-drag-callbacks.html">Using drag callbacks</a></li>
<li><a href="using-resize-callbacks.html">Using resize callbacks</a></li>
<li><a href="dynamic-grid-width.html">Dynamic grid width</a></li>
<li><a href="responsive.html">Responsive grid width</a></li>
<li><a href="SwapDrop.html">Grid with larger widgets swapping spots with smaller ones</a></li>
<li><a href="sticky-postion.html">Grid that allows widgets to be exactly placed anywhere</a></li>
</ul>
</body>
</html>

View File

@@ -0,0 +1,59 @@
<!doctype html>
<html>
<head>
<title>demo</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="3" data-sizey="3"></li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="3"></li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1"></li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1"></li>
<li data-row="4" data-col="3" data-sizex="1" data-sizey="1"></li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1"></li>
</ul>
</div>
<script type="text/javascript">
var api;
$(function () {
api = $(".gridster ul").gridster({
draggable: {
stop: function (event, ui, self) {
// $('.overlapped-area').hide();
this.$wrapper.addClass('sorting');
},
start: function (event, ui, self) {
this.$wrapper.removeClass('sorting');
// $('.overlapped-area').show();
}
},
collision: {
on_overlap_start: function (collider) {
// $(collider).data('graph').show();
//$(this).data('collision', collider);
},
on_overlap_stop: function (collider) {
//$(this).data('collision', null);
},
on_overlap: function (c) {
//$(this).data('collision', c);
}
}
}).data('gridster');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,71 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Multiple gridster intances &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Multiple gridster instances with different configurations</h1>
<p>When using multiple gridster instances on the same page you can scope the CSS code generated by gridster using <code>namespace</code> config
option.</p>
<h2>Demo 1</h2>
<div id="demo-1" class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
</ul>
</div>
<h2>Demo 2</h2>
<div id="demo-2" class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
</ul>
</div>
<script type="text/javascript">
var gridster = [];
$(function () {
gridster[0] = $("#demo-1 ul").gridster({
namespace: '#demo-1',
widget_base_dimensions: [100, 55],
widget_margins: [5, 5]
}).data('gridster');
gridster[1] = $("#demo-2 ul").gridster({
namespace: '#demo-2',
widget_base_dimensions: [200, 110],
widget_margins: [10, 10]
}).data('gridster');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,76 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Resize &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Resize with limits</h1>
<p>Use <code>resize.max_size</code> and <code>resize.min_size</code> config options or <code>data-max-sizex</code>, <code>data-max-sizey</code>,
<code>data-min-sizex</code> and <code>data-min-sizey</code> HTML attributes to limit widget dimensions when resizing.</p>
<p>If a global max_size is specified through the config option, can be overwrited in specified widgets with HTML data-attributes or using <code>set_widget_max_size</code>
method. This page has a global max limit of 4x4</p>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="6" data-min-sizex="2" data-min-sizey="6" data-max-sizex="2" data-max-sizey="6">
0
<br>
<small>Overridden to 2, 6</small>
</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2" data-max-sizex="6" data-max-sizey="2">
1
<br>
<small>Overridden max-size to 6, 2</small>
</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
<li data-row="1" data-col="5" data-sizex="3" data-sizey="3" data-min-sizex="3" data-min-sizey="3">
9
<br>
<small>Overridden min-size to 3, 3</small>
</li>
<li data-row="5" data-col="1" data-sizex="1" data-sizey="2">10</li>
<li data-row="4" data-col="3" data-sizex="1" data-sizey="2">11</li>
<li data-row="5" data-col="4" data-sizex="1" data-sizey="1">12</li>
<li data-row="6" data-col="2" data-sizex="3" data-sizey="1">13</li>
<li data-row="4" data-col="5" data-sizex="1" data-sizey="2">14</li>
<li data-row="6" data-col="5" data-sizex="1" data-sizey="1">15</li>
<li data-row="7" data-col="3" data-sizex="1" data-sizey="1">16</li>
</ul>
</div>
<script type="text/javascript">
var gridster;
$(function () {
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 100],
widget_margins: [5, 5],
helper: 'clone',
resize: {
enabled: true,
max_size: [4, 4],
min_size: [1, 1]
}
}).data('gridster');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,65 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Resize &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Resize</h1>
<p>Grab the right or bottom border and drag to the desired width or height.</p>
<div class="controls">
<button class="js-resize-random">Resize random widget</button>
</div>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
<li data-row="1" data-col="5" data-sizex="1" data-sizey="3">9</li>
</ul>
</div>
<script type="text/javascript">
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
</script>
<script type="text/javascript">
var gridster;
$(function () {
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 100],
widget_margins: [5, 5],
helper: 'clone',
resize: {
enabled: true
}
}).data('gridster');
$('.js-resize-random').on('click', function () {
gridster.resize_widget(gridster.$widgets.eq(getRandomInt(0, 9)),
getRandomInt(1, 4), getRandomInt(1, 4))
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,96 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Gridster Responsive Demo</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var gridster = null;
$(document).ready(function () {
gridster = $(".gridster ul").gridster({
widget_base_dimensions: ['auto', 140],
autogenerate_stylesheet: true,
min_cols: 1,
max_cols: 6,
widget_margins: [5, 5],
resize: {
enabled: true
}
}).data('gridster');
$('.gridster ul').css({'padding': '0'});
});
</script>
</head>
<body>
<div class="content">
<h1>Responsive Layout</h1>
<p>This demo represents using the branch in responsive mode. This makes the grid as wide as the screen and responds to changes in browser
width.</p>
</div>
<div class="gridster">
<ul>
<li data-sizey="2" data-sizex="2" data-col="4" data-row="1">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="1" data-row="3">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="2" data-row="3">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="2" data-sizex="2" data-col="1" data-row="1">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="3" data-row="1">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="3" data-row="3">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="4" data-row="3">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="6" data-row="1">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="5" data-row="3">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="3" data-row="2">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
<li data-sizey="1" data-sizex="1" data-col="6" data-row="2">
<div class="gridster-box">
<div class="handle-resize"></div>
</div>
</li>
</ul>
</div>
</body>
</html>

View File

@@ -0,0 +1,89 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Serialize &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
#log {
display: block;
width: 100%;
height: 20px;
margin-bottom: 20px;
-webkit-transition: height 0.3s ease;
-moz-transition: height 0.3s ease;
-ms-transition: height 0.3s ease;
-o-transition: height 0.3s ease;
transition: height 0.3s ease;
}
#log:focus {
height: 100px;
}
</style>
</head>
<body>
<h1>Serialize positions</h1>
<p>Use <code>serialize</code> method to get widget positions. It returns a Array of objects that can be used as a JSON object.</p>
<div class="controls">
<button class="js-seralize">Serialize</button>
</div>
<textarea id="log"></textarea>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
<li data-row="1" data-col="5" data-sizex="1" data-sizey="3">9</li>
<li data-row="5" data-col="1" data-sizex="1" data-sizey="2">10</li>
<li data-row="4" data-col="3" data-sizex="1" data-sizey="2">11</li>
<li data-row="5" data-col="4" data-sizex="1" data-sizey="1">12</li>
<li data-row="6" data-col="2" data-sizex="3" data-sizey="1">13</li>
<li data-row="4" data-col="5" data-sizex="1" data-sizey="2">14</li>
<li data-row="6" data-col="5" data-sizex="1" data-sizey="1">15</li>
<li data-row="7" data-col="3" data-sizex="1" data-sizey="1">16</li>
</ul>
</div>
<script type="text/javascript">
var gridster;
$(function () {
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 55],
widget_margins: [5, 5]
}).data('gridster');
$('.js-seralize').on('click', function () {
var s = gridster.serialize();
$('#log').val(JSON.stringify(s));
})
});
</script>
</body>
</html>

View File

@@ -0,0 +1,50 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; sticky position widgets &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Sticky position widgets</h1>
<p>Widgets can be moved to an exact postion on the grid and the grid will not attempt to collapse it down to a smaller size. Also widgets will not move out of the way automatically, but will move only on mouse up</p>
<div class="gridster">
<ul>
<ul class="task-card-list">
<li data-row="1" data-col="1" data-sizex="1" data-sizey="1" class="task-card">0</li>
<li data-row="1" data-col="2" data-sizex="1" data-sizey="1" class="task-card">1</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="1" class="task-card">2</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1" class="task-card">3</li>
<li data-row="2" data-col="1" data-sizex="1" data-sizey="1" class="task-card">4</li>
<li data-row="2" data-col="3" data-sizex="1" data-sizey="2" class="task-card">5</li>
<li data-row="2" data-col="4" data-sizex="1" data-sizey="1" class="task-card">6</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1" class="task-card">7</li>
<li data-row="3" data-col="2" data-sizex="1" data-sizey="1" class="task-card">8</li>
<li data-row="3" data-col="4" data-sizex="1" data-sizey="1" class="task-card">9</li>
</ul>
</div>
<script type="text/javascript">
var gridster;
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 100],
widget_margins: [5, 5],
shift_widgets_up: false,
shift_larger_widgets_down: false,
collision: {
wait_for_mouseup: true
}
}).data('gridster');
</script>
</body>
</html>

View File

@@ -0,0 +1,75 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Using drag callbacks &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
<style>
#log {
margin-top: 20px;
max-height: 400px;
overflow: auto;
max-width: 250px;
border: 1px solid #DDD;
}
</style>
</head>
<body>
<h1>Drag callbacks</h1>
<p>Drag some widgets and see the log below.</p>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
<li data-row="1" data-col="5" data-sizex="1" data-sizey="3">9</li>
</ul>
</div>
<h3>Log</h3>
<div id="log"></div>
<script type="text/javascript">
var gridster;
$(function () {
var log = document.getElementById('log');
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 55],
widget_margins: [5, 5],
draggable: {
start: function (e, ui, $widget) {
log.innerHTML = 'START position: ' + ui.position.top + ' ' + ui.position.left + "<br >" + log.innerHTML;
},
drag: function (e, ui, $widget) {
log.innerHTML = 'DRAG offset: ' + ui.pointer.diff_top + ' ' + ui.pointer.diff_left + "<br >" + log.innerHTML;
},
stop: function (e, ui, $widget) {
log.innerHTML = 'STOP position: ' + ui.position.top + ' ' + ui.position.left + "<br >" + log.innerHTML;
}
}
}).data('gridster');
});
</script>
</body>
</html>

View File

@@ -0,0 +1,78 @@
<!doctype html>
<html>
<head>
<title>Demo &raquo; Using resize callbacks &raquo; gridster.js</title>
<link rel="stylesheet" type="text/css" href="assets/css/demo.css">
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
<style>
#log {
margin-top: 20px;
max-height: 400px;
overflow: auto;
max-width: 250px;
border: 1px solid #DDD;
}
</style>
</head>
<body>
<h1>Resize callbacks</h1>
<p>Resize some widgets and see the log below.</p>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
<li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
<li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
<li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
<li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
<li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
<li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
<li data-row="1" data-col="5" data-sizex="1" data-sizey="3">9</li>
</ul>
</div>
<h3>Log</h3>
<div id="log"></div>
<script type="text/javascript">
var gridster;
$(function () {
var log = document.getElementById('log');
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [100, 55],
widget_margins: [5, 5],
resize: {
enabled: true,
start: function (e, ui, $widget) {
log.innerHTML = 'START position: ' + ui.position.top + ' ' + ui.position.left + "<br >" + log.innerHTML;
},
resize: function (e, ui, $widget) {
log.innerHTML = 'RESIZE offset: ' + ui.pointer.diff_top + ' ' + ui.pointer.diff_left + "<br >" + log.innerHTML;
},
stop: function (e, ui, $widget) {
log.innerHTML = 'STOP position: ' + ui.position.top + ' ' + ui.position.left + "<br >" + log.innerHTML;
}
}
}).data('gridster');
});
</script>
</body>
</html>

View File

@@ -1,121 +1,109 @@
/*! gridster.js - v0.5.6 - 2014-09-25
* http://gridster.net/
* Copyright (c) 2014 ducksboard; Licensed MIT */
/*! gridster.js - v0.6.10 - 2015-05-31
* https://dsmorse.github.io/gridster.js/
* Copyright (c) 2015 ducksboard; Licensed MIT */
.gridster {
position:relative;
position: relative;
}
.gridster > * {
margin: 0 auto;
-webkit-transition: height .4s, width .4s;
-moz-transition: height .4s, width .4s;
-o-transition: height .4s, width .4s;
-ms-transition: height .4s, width .4s;
transition: height .4s, width .4s;
-webkit-transition: height .4s, width .4s;
-moz-transition: height .4s, width .4s;
-o-transition: height .4s, width .4s;
-ms-transition: height .4s, width .4s;
transition: height .4s, width .4s;
}
.gridster .gs-w {
z-index: 2;
position: absolute;
z-index: 2;
position: absolute;
}
.gridster .preview-holder {
z-index: 1;
position: absolute;
background-color: #fff;
border-color: #fff;
opacity: 0.3;
}
.gridster .player-revert {
z-index: 10!important;
-webkit-transition: left .3s, top .3s!important;
-moz-transition: left .3s, top .3s!important;
-o-transition: left .3s, top .3s!important;
transition: left .3s, top .3s!important;
}
.gridster.collapsed {
height: auto !important;
}
.gridster.collapsed .gs-w {
position: static !important;
}
.ready .gs-w:not(.preview-holder) {
-webkit-transition: opacity .3s, left .3s, top .3s;
-moz-transition: opacity .3s, left .3s, top .3s;
-o-transition: opacity .3s, left .3s, top .3s;
transition: opacity .3s, left .3s, top .3s;
-webkit-transition: opacity .3s, left .3s, top .3s;
-moz-transition: opacity .3s, left .3s, top .3s;
-o-transition: opacity .3s, left .3s, top .3s;
transition: opacity .3s, left .3s, top .3s;
}
.ready .gs-w:not(.preview-holder),
.ready .resize-preview-holder {
-webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
}
.gridster .preview-holder {
z-index: 1;
position: absolute;
background-color: #fff;
border-color: #fff;
opacity: 0.3;
}
.gridster .player-revert {
z-index: 10!important;
-webkit-transition: left .3s, top .3s!important;
-moz-transition: left .3s, top .3s!important;
-o-transition: left .3s, top .3s!important;
transition: left .3s, top .3s!important;
}
.gridster .dragging,
.gridster .resizing {
z-index: 10!important;
-webkit-transition: all 0s !important;
-moz-transition: all 0s !important;
-o-transition: all 0s !important;
transition: all 0s !important;
z-index: 10!important;
-webkit-transition: all 0s !important;
-moz-transition: all 0s !important;
-o-transition: all 0s !important;
transition: all 0s !important;
}
.gs-resize-handle {
position: absolute;
z-index: 1;
position: absolute;
z-index: 1;
}
.gs-resize-handle-both {
width: 20px;
height: 20px;
bottom: -8px;
right: -8px;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
background-position: top left;
background-repeat: no-repeat;
cursor: se-resize;
z-index: 20;
width: 20px;
height: 20px;
bottom: -8px;
right: -8px;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
background-position: top left;
background-repeat: no-repeat;
cursor: se-resize;
z-index: 20;
}
.gs-resize-handle-x {
top: 0;
bottom: 13px;
right: -5px;
width: 10px;
cursor: e-resize;
top: 0;
bottom: 13px;
right: -5px;
width: 10px;
cursor: e-resize;
}
.gs-resize-handle-y {
left: 0;
right: 13px;
bottom: -5px;
height: 10px;
cursor: s-resize;
left: 0;
right: 13px;
bottom: -5px;
height: 10px;
cursor: s-resize;
}
.gs-w:hover .gs-resize-handle,
.resizing .gs-resize-handle {
opacity: 1;
opacity: 1;
}
.gs-resize-handle,
.gs-w.dragging .gs-resize-handle {
opacity: 0;
opacity: 0;
}
.gs-resize-disabled .gs-resize-handle {
display: none!important;
display: none!important;
}
[data-max-sizex="1"] .gs-resize-handle-x,
[data-max-sizey="1"] .gs-resize-handle-y,
[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle {
display: none !important;
display: none !important;
}
/* Uncomment this if you set helper : "clone" in draggable options */
/*.gridster .player {
opacity:0;
}
*/
*/
/*# sourceMappingURL=dist/jquery.gridster.css.map */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,2 @@
/*! gridster.js - v0.5.6 - 2014-09-25 - * http://gridster.net/ - Copyright (c) 2014 ducksboard; Licensed MIT */
.gridster{position:relative}.gridster>*{margin:0 auto;-webkit-transition:height .4s,width .4s;-moz-transition:height .4s,width .4s;-o-transition:height .4s,width .4s;-ms-transition:height .4s,width .4s;transition:height .4s,width .4s}.gridster .gs-w{z-index:2;position:absolute}.ready .gs-w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s;-moz-transition:opacity .3s,left .3s,top .3s;-o-transition:opacity .3s,left .3s,top .3s;transition:opacity .3s,left .3s,top .3s}.ready .gs-w:not(.preview-holder),.ready .resize-preview-holder{-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster .dragging,.gridster .resizing{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important}.gs-resize-handle{position:absolute;z-index:1}.gs-resize-handle-both{width:20px;height:20px;bottom:-8px;right:-8px;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=);background-position:top left;background-repeat:no-repeat;cursor:se-resize;z-index:20}.gs-resize-handle-x{top:0;bottom:13px;right:-5px;width:10px;cursor:e-resize}.gs-resize-handle-y{left:0;right:13px;bottom:-5px;height:10px;cursor:s-resize}.gs-w:hover .gs-resize-handle,.resizing .gs-resize-handle{opacity:1}.gs-resize-handle,.gs-w.dragging .gs-resize-handle{opacity:0}.gs-resize-disabled .gs-resize-handle{display:none!important}[data-max-sizex="1"] .gs-resize-handle-x,[data-max-sizey="1"] .gs-resize-handle-y,[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle{display:none!important}
/*! gridster.js - v0.6.10 - 2015-08-05 - * https://dsmorse.github.io/gridster.js/ - Copyright (c) 2015 ducksboard; Licensed MIT */
.gridster{position:relative}.gridster>*{-webkit-transition:height .4s,width .4s;-moz-transition:height .4s,width .4s;-o-transition:height .4s,width .4s;-ms-transition:height .4s,width .4s;transition:height .4s,width .4s}.gridster .gs-w{z-index:2;position:absolute}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster.collapsed{height:auto!important}.gridster.collapsed .gs-w{position:static!important}.ready .gs-w:not(.preview-holder),.ready .resize-preview-holder{-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .dragging,.gridster .resizing{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important}.gs-resize-handle{position:absolute;z-index:1}.gs-resize-handle-both{width:20px;height:20px;bottom:-8px;right:-8px;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=);background-position:top left;background-repeat:no-repeat;cursor:se-resize;z-index:20}.gs-resize-handle-x{top:0;bottom:13px;right:-5px;width:10px;cursor:e-resize}.gs-resize-handle-y{left:0;right:13px;bottom:-5px;height:10px;cursor:s-resize}.gs-w:hover .gs-resize-handle,.resizing .gs-resize-handle{opacity:1}.gs-resize-handle,.gs-w.dragging .gs-resize-handle{opacity:0}.gs-resize-disabled .gs-resize-handle,[data-max-sizex="1"] .gs-resize-handle-x,[data-max-sizey="1"] .gs-resize-handle-y,[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle{display:none!important}

View File

File diff suppressed because one or more lines are too long

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,21 @@
# coding: utf-8
require File.expand_path('../lib/gridster.js-rails/version', __FILE__)
Gem::Specification.new do |spec|
spec.name = "gridster.js-rails"
spec.version = Gridster::Rails::VERSION
spec.authors = ["dsmorse"]
spec.email = ['https://github.com/dsmorse']
spec.summary = %q{jQuery plugin for draggable grid layouts}
spec.description = %q{Gridster is a jQuery plugin that makes building intuitive draggable layouts from elements spanning multiple columns. You can even dynamically add and remove elements from the grid.}
spec.homepage = "https://github.com/dsmorse/gridster.js"
spec.licenses = ['MIT']
spec.files = Dir["{demos,lib,vendor}/**/*"] + ["LICENSE", "bower.json", "package.json", "CHANGELOG.md", "README.md"]
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 1.9"
spec.add_development_dependency "rake", "~> 10.0"
end

View File

@@ -0,0 +1,5 @@
module Gridster
module Rails
require "gridster.js-rails/engine"
end
end

View File

@@ -0,0 +1,6 @@
module Gridster
module Rails
class Engine < ::Rails::Engine
end
end
end

View File

@@ -0,0 +1,5 @@
module Gridster
module Rails
VERSION = "0.6.10"
end
end

View File

@@ -2,40 +2,57 @@
"name": "gridster",
"title": "gridster.js",
"description": "a drag-and-drop multi-column jQuery grid plugin",
"version": "0.5.6",
"homepage": "http://gridster.net/",
"version": "0.6.10",
"homepage": "https://dsmorse.github.io/gridster.js/",
"author": {
"name": "ducksboard",
"email": "hackers@ducksboard.com"
"name": "ducksboard"
},
"repository": {
"type": "git",
"url": "git://github.com/ducksboard/gridster.js.git"
"url": "git://github.com/dsmorse/gridster.js.git"
},
"bugs": {
"url": "https://github.com/ducksboard/gridster.js/issues"
"url": "https://github.com/dsmorse/gridster.js/issues"
},
"license": "MIT",
"licenses": [
{
"type": "MIT",
"url": "https://github.com/ducksboard/gridster.js/blob/master/LICENSE"
"url": "https://github.com/dsmorse/gridster.js/blob/master/LICENSE"
}
],
"keywords": [],
"dependencies": {
"jquery": "git+https://github.com/jquery/jquery.git#2.0.3"
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-uglify": "~0.2.0",
"grunt-contrib-jshint": "~0.3.0",
"grunt-contrib-concat": "~0.1.3",
"grunt-contrib-watch": "~0.3.1",
"grunt-contrib-cssmin": "~0.5.0",
"grunt-contrib-yuidoc": "~0.4.0",
"bower": "~0.9.2",
"qunitjs": "~1.11.0",
"grunt": "~0.4.5",
"grunt-bump": "0.0.11",
"grunt-conventional-changelog": "~1.0.0"
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-concat": "^0.5.0",
"grunt-contrib-copy": "^0.8.0",
"grunt-contrib-cssmin": "~0.10.0",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-less": "^1.0.1",
"grunt-contrib-qunit": "^0.7.0",
"grunt-contrib-uglify": "~0.6.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-yuidoc": "~0.7.0",
"grunt-conventional-changelog": "~1.0.0",
"grunt-gh-pages": "^0.10.0",
"grunt-shell": "^1.1.2",
"grunt-text-replace": "^0.4.0",
"jshint-stylish": "^1.0.1"
},
"scripts": {
"test": "grunt test"
},
"main": "dist/jquery.gridster.js",
"directories": {
"test": "test"
},
"jspm": {
"main": "jquery.gridster",
"directories": {
"lib": "dist"
}
}
}

View File

@@ -7,8 +7,11 @@
*/
;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
'use strict';
if(typeof exports === 'object') {
module.exports = factory(require('jquery'));
}
else if (typeof define === 'function' && define.amd) {
define('gridster-collision', ['jquery', 'gridster-coords'], factory);
} else {
root.GridsterCollision = factory(root.$ || root.jQuery,
@@ -16,7 +19,7 @@
}
}(this, function($, Coords) {
'use strict';
var defaults = {
colliders_context: document.body,
overlapping_region: 'C'
@@ -169,20 +172,22 @@
var area_coords = self.calculate_overlapped_area_coords(
player_coords, collider_coords);
var area = self.calculate_overlapped_area(area_coords);
var collider_data = {
area: area,
area_coords : area_coords,
region: region,
coords: collider_coords,
player_coords: player_coords,
el: $collider
};
if ( 0 !== area ) {
var collider_data = {
area: area,
area_coords : area_coords,
region: region,
coords: collider_coords,
player_coords: player_coords,
el: $collider
};
if (self.options.on_overlap) {
self.options.on_overlap.call(this, collider_data);
if (self.options.on_overlap) {
self.options.on_overlap.call(this, collider_data);
}
colliders_coords.push($collider_coords_ins);
colliders_data.push(collider_data);
}
colliders_coords.push($collider_coords_ins);
colliders_data.push(collider_data);
}
}

View File

@@ -7,14 +7,18 @@
*/
;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
'use strict';
if(typeof exports === 'object') {
module.exports = factory(require('jquery'));
}
else if (typeof define === 'function' && define.amd) {
define('gridster-coords', ['jquery'], factory);
} else {
root.GridsterCoords = factory(root.$ || root.jQuery);
}
}(this, function($) {
'use strict';
/**
* Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height)
* to simulate DOM elements on the screen.
@@ -55,8 +59,8 @@
if (el && !update) {
this.data = el.offset();
this.data.width = el.width();
this.data.height = el.height();
this.data.width = el[0].scrollWidth;
this.data.height = el[0].scrollHeight;
}
if (el && update && !not_update_offsets) {
@@ -67,8 +71,13 @@
var d = this.data;
typeof d.left === 'undefined' && (d.left = d.x1);
typeof d.top === 'undefined' && (d.top = d.y1);
if ( d.left === undefined ) {
d.left = d.x1;
}
if ( d.top === undefined ) {
d.top = d.y1;
}
this.coords.x1 = d.left;
this.coords.y1 = d.top;
@@ -115,7 +124,7 @@
return this.data('coords');
}
var ins = new Coords(this, arguments[0]);
var ins = new Coords(this);
this.data('coords', ins);
return ins;
};

View File

@@ -7,15 +7,18 @@
*/
;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
'use strict';
if(typeof exports === 'object') {
module.exports = factory(require('jquery'));
}
else if (typeof define === 'function' && define.amd) {
define('gridster-draggable', ['jquery'], factory);
} else {
root.GridsterDraggable = factory(root.$ || root.jQuery);
}
}(this, function($) {
'use strict';
var defaults = {
items: 'li',
distance: 1,
@@ -44,7 +47,7 @@
var idCounter = 0;
var uniqId = function() {
return ++idCounter + '';
}
};
/**
* Basic drag implementation for DOM elements inside a container.
@@ -76,15 +79,16 @@
* @constructor
*/
function Draggable(el, options) {
this.options = $.extend({}, defaults, options);
this.$document = $(document);
this.$container = $(el);
this.$dragitems = $(this.options.items, this.$container);
this.is_dragging = false;
this.player_min_left = 0 + this.options.offset_left;
this.id = uniqId();
this.ns = '.gridster-draggable-' + this.id;
this.init();
this.options = $.extend({}, defaults, options);
this.$document = $(document);
this.$container = $(el);
this.$scroll_container = this.options.scroll_container === window ?
$(window) : this.$container.closest(this.options.scroll_container);
this.is_dragging = false;
this.player_min_left = 0 + this.options.offset_left;
this.id = uniqId();
this.ns = '.gridster-draggable-' + this.id;
this.init();
}
Draggable.defaults = defaults;
@@ -98,8 +102,8 @@
this.disabled = false;
this.events();
$(window).bind(this.nsEvent('resize'),
throttle($.proxy(this.calculate_dimensions, this), 200));
$window.bind(this.nsEvent('resize'),
throttle($.proxy(this.calculate_dimensions, this), 200));
};
fn.nsEvent = function(ev) {
@@ -110,7 +114,7 @@
this.pointer_events = {
start: this.nsEvent('touchstart') + ' ' + this.nsEvent('mousedown'),
move: this.nsEvent('touchmove') + ' ' + this.nsEvent('mousemove'),
end: this.nsEvent('touchend') + ' ' + this.nsEvent('mouseup'),
end: this.nsEvent('touchend') + ' ' + this.nsEvent('mouseup')
};
this.$container.on(this.nsEvent('selectstart'),
@@ -130,8 +134,7 @@
};
fn.get_actual_pos = function($el) {
var pos = $el.position();
return pos;
return $el.position();
};
@@ -156,9 +159,13 @@
var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top);
var left = Math.round(this.el_init_offset.left +
diff_x - this.baseX + $(window).scrollLeft() - this.win_offset_x);
diff_x - this.baseX +
this.$scroll_container.scrollLeft() -
this.scroll_container_offset_x);
var top = Math.round(this.el_init_offset.top +
diff_y - this.baseY + $(window).scrollTop() - this.win_offset_y);
diff_y - this.baseY +
this.$scroll_container.scrollTop() -
this.scroll_container_offset_y);
if (this.options.limit) {
if (left > this.player_max_left) {
@@ -176,8 +183,10 @@
pointer: {
left: mouse_actual_pos.left,
top: mouse_actual_pos.top,
diff_left: diff_x + ($(window).scrollLeft() - this.win_offset_x),
diff_top: diff_y + ($(window).scrollTop() - this.win_offset_y)
diff_left: diff_x + (this.$scroll_container.scrollLeft() -
this.scroll_container_offset_x),
diff_top: diff_y + (this.$scroll_container.scrollTop() -
this.scroll_container_offset_y)
}
};
};
@@ -208,28 +217,36 @@
var area_size = 50;
var scroll_inc = 30;
var scrollDir = 'scroll' + capitalize(dir_prop);
var is_x = axis === 'x';
var window_size = is_x ? this.window_width : this.window_height;
var doc_size = is_x ? $(document).width() : $(document).height();
var scroller_size = is_x ? this.scroller_width : this.scroller_height;
var doc_size;
if (this.$scroll_container === window){
doc_size = is_x ? this.$scroll_container.width() :
this.$scroll_container.height();
}else{
doc_size = is_x ? this.$scroll_container[0].scrollWidth :
this.$scroll_container[0].scrollHeight;
}
var player_size = is_x ? this.$player.width() : this.$player.height();
var next_scroll;
var scroll_offset = $window['scroll' + capitalize(dir_prop)]();
var min_window_pos = scroll_offset;
var max_window_pos = min_window_pos + window_size;
var scroll_offset = this.$scroll_container[scrollDir]();
var min_scroll_pos = scroll_offset;
var max_scroll_pos = min_scroll_pos + scroller_size;
var mouse_next_zone = max_window_pos - area_size; // down/right
var mouse_prev_zone = min_window_pos + area_size; // up/left
var mouse_next_zone = max_scroll_pos - area_size; // down/right
var mouse_prev_zone = min_scroll_pos + area_size; // up/left
var abs_mouse_pos = min_window_pos + data.pointer[dir_prop];
var abs_mouse_pos = min_scroll_pos + data.pointer[dir_prop];
var max_player_pos = (doc_size - window_size + player_size);
var max_player_pos = (doc_size - scroller_size + player_size);
if (abs_mouse_pos >= mouse_next_zone) {
next_scroll = scroll_offset + scroll_inc;
if (next_scroll < max_player_pos) {
$window['scroll' + capitalize(dir_prop)](next_scroll);
this.$scroll_container[scrollDir](next_scroll);
this['scroll_offset_' + axis] += scroll_inc;
}
}
@@ -237,7 +254,7 @@
if (abs_mouse_pos <= mouse_prev_zone) {
next_scroll = scroll_offset - scroll_inc;
if (next_scroll > 0) {
$window['scroll' + capitalize(dir_prop)](next_scroll);
this.$scroll_container[scrollDir](next_scroll);
this['scroll_offset_' + axis] -= scroll_inc;
}
}
@@ -252,14 +269,13 @@
};
fn.calculate_dimensions = function(e) {
this.window_height = $window.height();
this.window_width = $window.width();
fn.calculate_dimensions = function() {
this.scroller_height = this.$scroll_container.height();
this.scroller_width = this.$scroll_container.width();
};
fn.drag_handler = function(e) {
var node = e.target.nodeName;
// skip if drag is disabled, or click was not done with the mouse primary button
if (this.disabled || e.which !== 1 && !isTouch) {
return;
@@ -315,7 +331,6 @@
var offset = this.$container.offset();
this.baseX = Math.round(offset.left);
this.baseY = Math.round(offset.top);
this.initial_container_width = this.options.container_width || this.$container.width();
if (this.options.helper === 'clone') {
this.$helper = this.$player.clone()
@@ -325,13 +340,10 @@
this.helper = false;
}
this.win_offset_y = $(window).scrollTop();
this.win_offset_x = $(window).scrollLeft();
this.scroll_offset_y = 0;
this.scroll_offset_x = 0;
this.scroll_container_offset_y = this.$scroll_container.scrollTop();
this.scroll_container_offset_x = this.$scroll_container.scrollLeft();
this.el_init_offset = this.$player.offset();
this.player_width = this.$player.width();
this.player_height = this.$player.height();
this.set_limits(this.options.container_width);
@@ -405,7 +417,7 @@
this.$container.off(this.ns);
this.$document.off(this.ns);
$(window).off(this.ns);
$window.off(this.ns);
$.removeData(this.$container, 'drag');
};
@@ -419,14 +431,26 @@
return this.options.ignore_dragging(event);
}
if (this.options.resize) {
return ! $(event.target).is(this.options.items);
}
return $(event.target).is(this.options.ignore_dragging.join(', '));
};
//jQuery adapter
$.fn.drag = function ( options ) {
$.fn.gridDraggable = function ( options ) {
return new Draggable(this, options);
};
$.fn.dragg = function (options) {
return this.each(function () {
if (!$.data(this, 'drag')) {
$.data(this, 'drag', new Draggable(this, options));
}
});
};
return Draggable;
}));

View File

@@ -1,117 +0,0 @@
.gridster {
position:relative;
}
.gridster > * {
margin: 0 auto;
-webkit-transition: height .4s, width .4s;
-moz-transition: height .4s, width .4s;
-o-transition: height .4s, width .4s;
-ms-transition: height .4s, width .4s;
transition: height .4s, width .4s;
}
.gridster .gs-w {
z-index: 2;
position: absolute;
}
.ready .gs-w:not(.preview-holder) {
-webkit-transition: opacity .3s, left .3s, top .3s;
-moz-transition: opacity .3s, left .3s, top .3s;
-o-transition: opacity .3s, left .3s, top .3s;
transition: opacity .3s, left .3s, top .3s;
}
.ready .gs-w:not(.preview-holder),
.ready .resize-preview-holder {
-webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
}
.gridster .preview-holder {
z-index: 1;
position: absolute;
background-color: #fff;
border-color: #fff;
opacity: 0.3;
}
.gridster .player-revert {
z-index: 10!important;
-webkit-transition: left .3s, top .3s!important;
-moz-transition: left .3s, top .3s!important;
-o-transition: left .3s, top .3s!important;
transition: left .3s, top .3s!important;
}
.gridster .dragging,
.gridster .resizing {
z-index: 10!important;
-webkit-transition: all 0s !important;
-moz-transition: all 0s !important;
-o-transition: all 0s !important;
transition: all 0s !important;
}
.gs-resize-handle {
position: absolute;
z-index: 1;
}
.gs-resize-handle-both {
width: 20px;
height: 20px;
bottom: -8px;
right: -8px;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
background-position: top left;
background-repeat: no-repeat;
cursor: se-resize;
z-index: 20;
}
.gs-resize-handle-x {
top: 0;
bottom: 13px;
right: -5px;
width: 10px;
cursor: e-resize;
}
.gs-resize-handle-y {
left: 0;
right: 13px;
bottom: -5px;
height: 10px;
cursor: s-resize;
}
.gs-w:hover .gs-resize-handle,
.resizing .gs-resize-handle {
opacity: 1;
}
.gs-resize-handle,
.gs-w.dragging .gs-resize-handle {
opacity: 0;
}
.gs-resize-disabled .gs-resize-handle {
display: none!important;
}
[data-max-sizex="1"] .gs-resize-handle-x,
[data-max-sizey="1"] .gs-resize-handle-y,
[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle {
display: none !important;
}
/* Uncomment this if you set helper : "clone" in draggable options */
/*.gridster .player {
opacity:0;
}
*/

View File

@@ -1,13 +1,16 @@
;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
'use strict';
if(typeof exports === 'object') {
module.exports = factory(require('jquery'), require('./jquery.gridster.js'));
}
else if (typeof define === 'function' && define.amd) {
define(['jquery', 'gridster'], factory);
} else {
root.Gridster = factory(root.$ || root.jQuery, root.Gridster);
}
}(this, function($, Gridster) {
'use strict';
var fn = Gridster.prototype;
fn.widgets_in_col = function(col) {
@@ -34,32 +37,6 @@
return false;
};
fn.widgets_in_range = function(col1, row1, col2, row2) {
var valid_cols = [];
var valid_rows = [];
var $widgets = $([]);
var c, r, $w, wgd;
for (c = col2; c >= col1; c--) {
for (r = row2; r >= row1; r--) {
$w = this.is_widget(c, r);
if ($w !== false) {
wgd = $w.data('coords').grid;
if (wgd.col >= col1 && wgd.col <= col2 &&
wgd.row >= row1 && wgd.row <= row2
) {
$widgets = $widgets.add($w);
}
}
}
}
return $widgets;
};
fn.get_bottom_most_occupied_cell = function() {
var row = 0;
var col = 0;
@@ -108,7 +85,7 @@
};
fn.next_position_in_range = function(size_x, size_y, max_rows) {
fn.next_position_in_range = function(size_x, size_y) {
size_x || (size_x = 1);
size_y || (size_y = 1);
var ga = this.gridmap;
@@ -117,12 +94,12 @@
var rows_l;
for (var c = 1; c < cols_l; c++) {
rows_l = max_rows || ga[c].length;
rows_l = this.options.max_rows || ga[c].length;
for (var r = 1; r <= rows_l; r++) {
var can_move_to = this.can_move_to({
size_x: size_x,
size_y: size_y
}, c, r, max_rows);
}, c, r);
if (can_move_to) {
valid_pos.push({
@@ -158,7 +135,6 @@
fn.closest_to_left = function(col, row) {
var cols_l = this.gridmap.length - 1;
if (!this.gridmap[col]) { return false; }
for (var c = col; c >= 1; c--) {

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
/*! gridster.js - v0.6.10 - 2015-05-31
* https://dsmorse.github.io/gridster.js/
* Copyright (c) 2015 ducksboard; Licensed MIT */
.gridster {
position:relative;
& > * {
-webkit-transition: height .4s, width .4s;
-moz-transition: height .4s, width .4s;
-o-transition: height .4s, width .4s;
-ms-transition: height .4s, width .4s;
transition: height .4s, width .4s;
}
.gs-w {
z-index: 2;
position: absolute;
}
.preview-holder {
z-index: 1;
position: absolute;
background-color: #fff;
border-color: #fff;
opacity: 0.3;
}
.player-revert {
z-index: 10!important;
-webkit-transition: left .3s, top .3s!important;
-moz-transition: left .3s, top .3s!important;
-o-transition: left .3s, top .3s!important;
transition: left .3s, top .3s!important;
}
}
.gridster.collapsed {
height: auto !important;
.gs-w {
position: static !important;
}
}
.ready {
.gs-w:not(.preview-holder) {
-webkit-transition: opacity .3s, left .3s, top .3s;
-moz-transition: opacity .3s, left .3s, top .3s;
-o-transition: opacity .3s, left .3s, top .3s;
transition: opacity .3s, left .3s, top .3s;
}
}
.ready .gs-w:not(.preview-holder),.ready .resize-preview-holder {
-webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
}
.gridster .dragging,.gridster .resizing {
z-index: 10!important;
-webkit-transition: all 0s !important;
-moz-transition: all 0s !important;
-o-transition: all 0s !important;
transition: all 0s !important;
}
.gs-resize-handle {
position: absolute;
z-index: 1;
}
.gs-resize-handle-both {
width: 20px;
height: 20px;
bottom: -8px;
right: -8px;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
background-position: top left;
background-repeat: no-repeat;
cursor: se-resize;
z-index: 20;
}
.gs-resize-handle-x {
top: 0;
bottom: 13px;
right: -5px;
width: 10px;
cursor: e-resize;
}
.gs-resize-handle-y {
left: 0;
right: 13px;
bottom: -5px;
height: 10px;
cursor: s-resize;
}
.gs-w:hover .gs-resize-handle,.resizing .gs-resize-handle {
opacity: 1;
}
.gs-resize-handle,.gs-w.dragging .gs-resize-handle {
opacity: 0;
}
.gs-resize-disabled {
.gs-resize-handle {
display: none!important;
}
}
[data-max-sizex="1"] .gs-resize-handle-x,[data-max-sizey="1"] .gs-resize-handle-y,[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle {
display: none !important;
}
/* Uncomment this if you set helper : "clone" in draggable options */
/*.gridster .player {
opacity:0;
}
*/

View File

@@ -1,72 +1,85 @@
;(function(window, undefined) {
(function (window, undefined) {
'use strict';
/* Delay, debounce and throttle functions taken from underscore.js
*
* Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and
* Investigative Reporters & Editors
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* Delay, debounce and throttle functions taken from underscore.js
*
* Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and
* Investigative Reporters & Editors
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
window.delay = function (func, wait) {
var args = Array.prototype.slice.call(arguments, 2);
return setTimeout(function () {
return func.apply(null, args);
}, wait);
};
window.delay = function(func, wait) {
var args = Array.prototype.slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
window.debounce = function (func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
if (immediate && !timeout) {
func.apply(context, args);
}
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
window.debounce = function(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
if (immediate && !timeout) func.apply(context, args);
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
window.throttle = function(func, wait) {
var context, args, timeout, throttling, more, result;
var whenDone = debounce(
function(){ more = throttling = false; }, wait);
return function() {
context = this; args = arguments;
var later = function() {
timeout = null;
if (more) func.apply(context, args);
whenDone();
};
if (!timeout) timeout = setTimeout(later, wait);
if (throttling) {
more = true;
} else {
result = func.apply(context, args);
}
whenDone();
throttling = true;
return result;
};
};
window.throttle = function (func, wait) {
var context, args, timeout, throttling, more, result;
var whenDone = debounce(
function () {
more = throttling = false;
}, wait);
return function () {
context = this;
args = arguments;
var later = function () {
timeout = null;
if (more) {
func.apply(context, args);
}
whenDone();
};
if (!timeout) {
timeout = setTimeout(later, wait);
}
if (throttling) {
more = true;
} else {
result = func.apply(context, args);
}
whenDone();
throttling = true;
return result;
};
};
})(window);

View File

@@ -0,0 +1,53 @@
//Based on https://github.com/jonnyreeves/qunit-require
/* global require, QUnit*/
'use strict';
require.config({
//set the baseUrl to the src dir so that gridster
//AMD modules can be found.
baseUrl: '../src/',
paths: {
'QUnit': '../libs/qunit/qunit/qunit',
'jquery': '../libs/jquery/dist/jquery',
'gridster': 'jquery.gridster'
},
map: {
// '*' means all modules will get 'jquery-private'
// for their 'jquery' dependency.
'*': { 'jquery': '../test/jquery-private' },
// 'jquery-private' wants the real jQuery module
// though. If this line was not here, there would
// be an unresolvable cyclic dependency.
'../test/jquery-private': { 'jquery': 'jquery' }
},
shim: {
'QUnit': {
exports: 'QUnit',
init: function() {
QUnit.config.autoload = false;
QUnit.config.autostart = false;
}
}
}
});
/*
Load all of our require'd files
We have to load all of the gridster jquery.* modules so
that they are defined for when gridster needs them.
Lastly, load the testsuite which defines some tests.
*/
require([
'QUnit',
'utils',
'jquery.coords',
'jquery.collision',
'jquery.draggable',
'../test/testsuite'
//Require'd files are passed as args, but we don't use them.
], function(QUnit/*, utils, coords, collision, draggable, testsuite*/) {
QUnit.load();
QUnit.start();
}
);

4
lib/gridster/test/jquery-private.js vendored Normal file
View File

@@ -0,0 +1,4 @@
define(['jquery'], function (jq) {
'use strict';
return jq.noConflict( true );
});

View File

@@ -1,38 +0,0 @@
/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/
/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/
/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/
(function($) {
/*
======== A Handy Little QUnit Reference ========
http://docs.jquery.com/QUnit
Test methods:
expect(numAssertions)
stop(increment)
start(decrement)
Test assertions:
ok(value, [message])
equal(actual, expected, [message])
notEqual(actual, expected, [message])
deepEqual(actual, expected, [message])
notDeepEqual(actual, expected, [message])
strictEqual(actual, expected, [message])
notStrictEqual(actual, expected, [message])
raises(block, [expected], [message])
*/
module('jQuery#gridster', {
setup: function() {
this.el = $('#qunit-fixture').find(".wrapper ul");
}
});
// test('is chainable', 1, function() {
// // Not a bad test to run on collection methods.
// strictEqual(this.el, this.el.gridster(), 'should be chaninable');
// });
}(jQuery));

View File

@@ -2,30 +2,17 @@
<html>
<head>
<meta charset="utf-8">
<title>gridster.js Test Suite</title>
<!-- Load local jQuery, removing access to $ (use jQuery, not $). -->
<script src="../libs/jquery/jquery.js"></script>
<script>jQuery.noConflict()</script>
<script type="text/javascript" src="../libs/jquery/jquery.js"></script>
<script src="../dist/jquery.gridster.min.js" type="text/javascript" charset="utf-8"></script>
<title>gridster.js AMD Test Suite</title>
<link rel="stylesheet" type="text/css" href="../dist/jquery.gridster.css">
<!-- Load local QUnit (grunt requires v1.0.0 or newer). -->
<link rel="stylesheet" href="../libs/qunit/qunit.css" media="screen">
<script src="../libs/qunit/qunit.js"></script>
<!-- Load local lib and tests. -->
<script src="../src/jquery.gridster.js"></script>
<script src="jquery.gridster_test.js"></script>
<link rel="stylesheet" href="../libs/qunit/qunit/qunit.css" media="screen">
<!-- Load requirejs which will load amd-main.js and start from there-->
<script data-main="amd-main.js" src="../libs/requirejs/require.js"></script>
</head>
<body>
<h1 id="qunit-header">gridster.js Test Suite</h1>
<h1 id="qunit-header">gridster.js AMD Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>

View File

@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>gridster.js Test Suite</title>
<!-- Load JQuery dependency. -->
<script src="../libs/jquery/dist/jquery.js"></script>
<script>jQuery.noConflict()</script>
<!-- load the gridster source files, run the tests against the broken out javascipt in the source dir-->
<script src="../src/jquery.coords.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/jquery.collision.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/utils.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/jquery.draggable.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/jquery.gridster.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href="../src/jquery.gridster.css">
<!-- Load QUnit dependency. -->
<link rel="stylesheet" href="../libs/qunit/qunit/qunit.css" media="screen">
<script src="../libs/qunit/qunit/qunit.js"></script>
<!-- Load local lib and tests. -->
<script src="jquery.gridster_test.js"></script>
</head>
<body>
<h1 id="qunit-header">gridster.js Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">
<div class="wrapper">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="2"></li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="2"></li>
</ul>
</div>
</div>
<div id="qunit-testresult"></div>
</body>
</html>

View File

@@ -0,0 +1,395 @@
//jshint quotmark:false
/*global module:false, test:false */
/*global ok:false, equal:false, notEqual:false, deepEqual:false*/
/*global notDeepEqual:false */
(function ($) {
'use strict';
/*
======== A Handy Little QUnit Reference ========
http://docs.jquery.com/QUnit
Test methods:
expect(numAssertions)
stop(increment)
start(decrement)
Test assertions:
ok(value, [message])
equal(actual, expected, [message])
notEqual(actual, expected, [message])
deepEqual(actual, expected, [message])
notDeepEqual(actual, expected, [message])
strictEqual(actual, expected, [message])
notStrictEqual(actual, expected, [message])
raises(block, [expected], [message])
*/
module('jQuery#gridster', {
setup: function () {
this.el = $('#qunit-fixture').find(".wrapper ul");
this.serialization = [
{name: "A", col: "1", row: "1", size_x: "2", size_y: "2"},
{name: "B", col: "4", row: "1", size_x: "1", size_y: "2"},
{name: "C", col: "10", row: "10", size_x: "10", size_y: "10"},
{name: "D", col: "3", row: "1", size_x: "1", size_y: "1"},
{name: "E", col: "2", row: "3", size_x: "3", size_y: "1"}
];
this.serialization_small = [
{col: 1, row: 1, size_x: 2, size_y: 2},
{col: 3, row: 1, size_x: 1, size_y: 2},
{col: 6, row: 1, size_x: 1, size_y: 1}
];
}
});
test('can count and clear widgets', 2, function () {
var grid = this.el.gridster().data('gridster');
equal(grid.get_num_widgets(), 2, 'Count the default widgets from the HTML config');
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
});
test('Above and below', 12, function () {
var grid = this.el.gridster({ max_cols: 4, max_rows: 4, widget_base_dimensions: [100, 55]}).data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
$.each(this.serialization, function () {
grid.add_widget('<li />', this.size_x, this.size_y, this.col, this.row);
});
equal(grid.get_num_widgets(), this.serialization.length, 'Loaded the widgets for the test');
var widgets_above = $([]);
//the call here checks above as the user see's it on the screen which will check row below 4
grid.for_each_widget_above(3, 4, function(tcol, trow) {
widgets_above = widgets_above.add(this);
});
//widgets B (3,1) & E (2-4, 3) should be below cell 3,4
equal(2, widgets_above.length);
var widgets_found_above = grid.serialize(widgets_above);
equal(widgets_found_above[1].col, parseInt(this.serialization[4].col));
equal(widgets_found_above[1].row, parseInt(this.serialization[4].row));
equal(widgets_found_above[1].size_x, parseInt(this.serialization[4].size_x));
equal(widgets_found_above[1].size_y, parseInt(this.serialization[4].size_y));
var widgets_below = $([]);
grid.for_each_widget_below(3, 2, function(tcol, trow) {
widgets_below = widgets_below.add(this);
});
//widget E (2-4, 3) should be above cell 3,2
equal(1, widgets_below.length);
var widgets_found_below = grid.serialize(widgets_below);
equal(widgets_found_below[0].col, parseInt(this.serialization[4].col));
equal(widgets_found_below[0].row, parseInt(this.serialization[4].row));
equal(widgets_found_below[0].size_x, parseInt(this.serialization[4].size_x));
equal(widgets_found_below[0].size_y, parseInt(this.serialization[4].size_y));
});
test('get_widgets_from', 5, function () {
var input = {col: 2, row: 1, size_x: 3, size_y: 1};
var grid = this.el.gridster().data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input.size_x, input.size_y, input.col, input.row);
var widget = grid.get_widgets_at_cell(input.col, input.row);
// normally you would call parseInt on a return from
// .attr(), but qunit takes care of it for us
equal(widget.attr('data-row'), input.row);
equal(widget.attr('data-col'), input.col);
equal(widget.attr('data-sizex'), input.size_x);
equal(widget.attr('data-sizey'), input.size_y);
});
test('get_cells_occupied', 3, function () {
var input = {col: 2, row: 3, size_x: 3, size_y: 1};
var grid = this.el.gridster().data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
var cellsUsed = grid.get_cells_occupied(input);
deepEqual(cellsUsed.rows, [3]);
deepEqual(cellsUsed.cols, [2,3,4]);
});
test('get_highest_occupied_cell', 1, function () {
var grid = this.el.gridster().data('gridster');
deepEqual(grid.get_min_col(), 1);
});
test('get_highest_occupied_cell', 1, function () {
var grid = this.el.gridster().data('gridster');
deepEqual(grid.get_highest_occupied_cell(), {col: 3, row: 2});
});
//todo tests to add:
// setup_resize & add_resize_handle
// get_min_col
// shift_cols
// get_widgets_from_DOM dom_to_coords, get_widgets_from_DOM set_dom_grid_height set_dom_grid_width
// generate_stylesheet
// set_num_columns
test('add_style_tag', 4, function () {
var grid = this.el.gridster({autogenerate_stylesheet: true}).data('gridster');
var generatedStyleSheet = $('#gridster-stylesheet');
notEqual(generatedStyleSheet, null);
ok(generatedStyleSheet.length > 0);
grid.destroy();
grid = this.el.gridster({autogenerate_stylesheet: true, namespace: 'qunit'}).data('gridster');
generatedStyleSheet = $('#gridster-stylesheet-qunit');
notEqual(generatedStyleSheet, null);
ok(generatedStyleSheet.length > 0);
});
test('resize_widget', 4, function () {
this.resizeGrid = [
{col: 1, row: 1, size_x: 1, size_y: 1},
{col: 2, row: 1, size_x: 1, size_y: 1},
{col: 3, row: 1, size_x: 1, size_y: 1},
{col: 1, row: 2, size_x: 1, size_y: 1},
{col: 2, row: 2, size_x: 1, size_y: 1},
{col: 3, row: 2, size_x: 1, size_y: 1},
{col: 1, row: 3, size_x: 1, size_y: 1},
{col: 2, row: 3, size_x: 1, size_y: 1},
{col: 3, row: 3, size_x: 1, size_y: 1}
];
var grid = this.el.gridster({widget_base_dimensions: [100, 55]}).data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
var numBefore = grid.get_num_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
$.each(this.resizeGrid, function () {
grid.add_widget('<li />', this.size_x, this.size_y, this.col, this.row);
});
equal(grid.get_num_widgets(), numBefore + this.resizeGrid.length, 'Loading the widgets to prepare for tests');
//check for widgets in the space it will occupy
var widgets = grid.get_widgets_in_range(1,1,2,2);
var numberInSpaceBefore = widgets.length;
equal(numberInSpaceBefore, 4, 'Expect there to be four widgets in the first two rows and cols');
//get the widget from 1,1 and resize it.
grid.resize_widget(grid.get_widgets_at_cell(1, 1), 2, 2);
//check for widgets in the space it will occupy
widgets = grid.get_widgets_in_range(1,1,2,2);
var numberInSpaceAfter = widgets.length;
equal(numberInSpaceAfter, 1, 'Expected a single widget in the expanded area');
});
test('can serialize correctly', 4, function () {
var grid = this.el.gridster({widget_base_dimensions: [100, 55]}).data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
var numBefore = grid.get_num_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
$.each(this.serialization_small, function () {
grid.add_widget('<li />', this.size_x, this.size_y, this.col, this.row);
});
equal(grid.get_num_widgets(), numBefore + this.serialization_small.length);
var serialized = grid.serialize();
equal(grid.get_num_widgets(), serialized.length);
deepEqual(serialized, this.serialization_small);
});
test('can serialize extended properties', 4, function () {
var input = [{col: 6, row: 3, size_x: 1, size_y: 1}];
var grid = this.el.gridster({widget_base_dimensions: [100, 55], serialize_params: function($w, wgd) {
return {
col: wgd.col,
row: wgd.row
};}}).data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input[0].size_x, input[0].size_y, input[0].col, input[0].row);
var serialized = grid.serialize();
//due to custom serialization, input and output should NOT match
notDeepEqual(serialized, input);
equal(serialized[0].col, 6);
equal(serialized[0].size_x, undefined);
});
test('When Adding widgets rows auto condense', 2, function () {
var input = [{col: 6, row: 3, size_x: 1, size_y: 1}];
var output = [{col: 6, row: 1, size_x: 1, size_y: 1}];
var grid = this.el.gridster().data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
//make sure we are empty
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input[0].size_x, input[0].size_y, input[0].col, input[0].row);
var serialized = grid.serialize();
deepEqual(serialized, output);
});
test('When Adding widgets rows static placement is supported', 2, function () {
var input = [{col: 6, row: 3, size_x: 1, size_y: 1}];
var grid = this.el.gridster().data('gridster');
grid.options.shift_widgets_up = false;
//remove any widgets from the html config
grid.remove_all_widgets();
//make sure we are empty
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input[0].size_x, input[0].size_y, input[0].col, input[0].row);
var serialized = grid.serialize();
deepEqual(serialized, input);
});
test('When Adding widgets cols are respected', 2, function () {
var input = [{col: 6, row: 1, size_x: 1, size_y: 1}];
var grid = this.el.gridster().data('gridster');
//remove any widgets from the html config
grid.remove_all_widgets();
//make sure we are empty
equal(grid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
grid.add_widget('<li />', input[0].size_x, input[0].size_y, input[0].col, input[0].row);
var serialized = grid.serialize();
deepEqual(serialized, input);
});
test('can_move_to', 7, function () {
var input = {col: 6, row: 1, size_x: 1, size_y: 1};
var defaultGrid = this.el.gridster().data('gridster');
//remove any widgets from the html config
defaultGrid.remove_all_widgets();
//make sure we are empty
equal(defaultGrid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
//check with the default config we can place an widget in a skipped col
var canMove = defaultGrid.can_move_to({size_x: input.size_x, size_y: input.size_y}, input.col, input.row);
equal(canMove, true, 'with the default config we can place an widget in a skipped col');
//check with the default config we can not place an widget in a skipped row
canMove = defaultGrid.can_move_to({size_x: input.size_x, size_y: input.size_y}, input.col, input.row+3);
equal(canMove, true, 'with the default config we can not place an widget in a skipped row');
defaultGrid.destroy();
//now repeat the tests with custom settings
var customGrid = this.el.gridster({max_rows : 2, max_cols : 4}).data('gridster');
//remove any widgets from the html config
customGrid.remove_all_widgets();
//make sure we are empty
equal(customGrid.get_num_widgets(), 0, 'Clearing the widgets to prepare for tests');
//check with the Custom config we can place an widget outside the grid
canMove = customGrid.can_move_to({size_x: input.size_x, size_y: input.size_y}, input.col, input.row);
equal(canMove, false, 'with the Custom config we can place an widget outside the grid');
//check with the custom config we can not place an widget outside the grid
canMove = customGrid.can_move_to({size_x: input.size_x, size_y: input.size_y}, 1, input.row+3);
equal(canMove, false, 'with the custom config we can not place an widget outside the grid');
//check to see if we can't move an widget to where there is one
customGrid.add_widget('<li />', 1, 1, 1, 1);
canMove = customGrid.can_move_to({size_x: 1, size_y: 1}, 1, 1);
equal(canMove, false, 'we cant move an widget to where there is one');
});
test('is chainable', 1, function () {
// Not a bad test to run on collection methods.
strictEqual(this.el, this.el.gridster(), 'should be chaninable');
});
test('is Responsive', 1, function () {
var grid = this.el.gridster(
{autogenerate_stylesheet: true,
widget_base_dimensions: ['auto', 'auto'],
max_cols: 4}).data('gridster');
equal(grid.is_responsive(), true);
});
test('Gridster.sort_by_row_asc', 4, function (assert) {
var sorted = Gridster.sort_by_row_asc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'A,B,D,E,C';
//since the test data contains 3 #1, they could be in any order
ok( result.substring(0,5).indexOf('A') > -1, 'A is found in within the first 3 results');
ok( result.substring(0,5).indexOf('B') > -1, 'B is found in within the first 3 results');
ok( result.substring(0,5).indexOf('D') > -1, 'D is found in within the first 3 results');
//check the last to chars
equal( result.substring(6), expected.substring(6), 'E,C are the last two - In that order');
});
test('Gridster.sort_by_row_and_col_asc', function (assert) {
var sorted = Gridster.sort_by_row_and_col_asc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'A,D,B,E,C';
assert.equal(result, expected);
});
test('Gridster.sort_by_col_asc', function (assert) {
var sorted = Gridster.sort_by_col_asc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'A,E,D,B,C';
assert.equal(result, expected);
});
test('Gridster.sort_by_row_desc',4, function (assert) {
var sorted = Gridster.sort_by_row_desc(this.serialization);
var result = pickup(sorted, 'name').join(',');
var expected = 'C,E,A,B,D';
//since the test data contains 3 #1, they could be in any order
ok( result.substring(4).indexOf('A') > -1, 'A is found in within the last 3 results');
ok( result.substring(4).indexOf('B') > -1, 'B is found in within the last 3 results');
ok( result.substring(4).indexOf('D') > -1, 'D is found in within the last 3 results');
//check the last to chars
equal( result.substring(0,3), expected.substring(0,3), 'C,E are the first two - In that order');
});
// errors
test('sort_by_row_asc: Throws not exists property', function (assert) {
assert.throws(function () {
//missing col
var data = [{row: 1, size_x: 1, size_y: 1}, {col: 2, row: 1, size_x: 1, size_y: 1}];
Gridster.sort_by_row_asc(data);
},
Error,
'raise error not exists required property'
);
});
test('sort_by_row_asc: Throws invalid type of value', function (assert) {
var secWidget = {col: 2, row: 1, size_x: 1, size_y: 1};
// inconvertible types
assert.throws(function () {
//col is not a number
Gridster.sort_by_row_asc([{col: "AAA", row: 1, size_x: 1, size_y: 1}, secWidget]);
}, Error, 'raise error inconvertible types' );
// null
assert.throws(function () {
// coll is null
Gridster.sort_by_row_asc([{col: null, row: 1, size_x: 1, size_y: 1}, secWidget]);
}, Error, 'raise error value is null' );
// array
assert.throws(function () {
//col does not accept an array
Gridster.sort_by_row_asc([{col: [1, 2, 3], row: 1, size_x: 1, size_y: 1}, secWidget]);
}, Error, 'raise error value is array' );
// object
assert.throws(function () {
//col does not accept an onbject
Gridster.sort_by_row_asc([{col: {k: 1}, row: 1, size_x: 1, size_y: 1}, secWidget]);
},Error, 'raise error value is object');
});
// helper
function pickup (data, prop) {
return data.map(function (elm) {
return elm[prop];
});
}
}(jQuery));

View File

@@ -0,0 +1,200 @@
/* global u, SPEED*/
'use strict';
window.serialization = {
'default': function() {
return [
{name: 'A', col: 1, row: 1, size_x: 1, size_y: 2},
{name: 'B', col: 2, row: 1, size_x: 3, size_y: 2},
{name: 'C', col: 5, row: 1, size_x: 3, size_y: 2},
{name: 'D', col: 8, row: 1, size_x: 2, size_y: 1},
{name: 'E', col: 1, row: 3, size_x: 4, size_y: 1},
{name: 'F', col: 10, row: 1, size_x: 1, size_y: 2},
{name: 'G', col: 8, row: 2, size_x: 2, size_y: 1},
{name: 'H', col: 5, row: 3, size_x: 3, size_y: 2},
{name: 'I', col: 8, row: 3, size_x: 1, size_y: 1},
{name: 'J', col: 9, row: 3, size_x: 2, size_y: 2},
{name: 'K', col: 1, row: 4, size_x: 1, size_y: 3}
];
}
};
window.u = {
pick: function(data, prop) {
return data.map(function(elm) {
return elm[prop];
});
},
getRandomColor: function() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.round(Math.random() * 10)];
}
return color;
},
createGridster: function(config, serialize, fromDom) {
var defaults = {
widget_margins: [5, 5],
widget_base_dimensions: [100, 55],
min_cols: 10,
max_cols: 10
};
serialize || (serialize = window.serialization.default());
var widgets = [];
$.each(serialize, function(i, w) {
widgets.push(['<li>' + w.name + '</li>', w.size_x, w.size_y, w.col, w.row]);
});
this.$fixture = $('#fixture');
this.$fixture.html('<div class="gridster"><ul></ul></div>');
this.$el = $('.gridster > ul');
if (fromDom) {
var html = [];
$.each(serialize, function(i, w) {
html.push('<li data-col="' + w.col + '" data-row="' + w.row + '" data-sizex="' + w.size_x + '" data-sizey="' + w.size_y + '">' + w.name + '</li>');
});
this.$el.html(html.join('\n'));
}
this.gridster = this.$el.gridster(
$.extend({}, defaults, config)).data('gridster');
if (!fromDom) {
$.each(widgets, function(i, widget) {
this.gridster.add_widget.apply(this.gridster, widget);
}.bind(this));
}
this.drag_from_to = u._dragFromTo;
return this.gridster;
},
createEvent: function(type, offset) {
var event = document.createEvent('MouseEvents');
event.initMouseEvent(type, true, true, window, 0, 0, 0,
offset.left, offset.top, false, false, false, false, 0, null);
return event;
},
dispatchEvent: function(elem, type, event) {
if (elem.dispatchEvent) {
elem.dispatchEvent(event);
} else if (elem.fireEvent) {
elem.fireEvent('on' + type, event);
}
},
_dragFromTo: function(fromCoords, toCoords) {
var d = $.Deferred();
var gridster = this.gridster;
var $el;
function getMousePos(coords) {
var size = gridster.options.widget_base_dimensions;
var margin = gridster.options.widget_margins;
var left = ((coords[0] - 1) * size[0]) + (margin[0] * ((coords[0] * 2) - 1));
var top = ((coords[1] - 1) * size[1]) + (margin[1] * ((coords[1] * 2) - 1));
var parentOffset = gridster.$wrapper.offset();
return {
left: parentOffset.left + left + 20,
top: parentOffset.top + top + 20
};
}
function addPoint(offset) {
$('<span/>').css({
left: offset.left + 'px',
top: offset.top + 'px',
width: '2px',
height: '2px',
background: 'red',
display: 'inline-block',
position: 'absolute',
zIndex: '9999'
}).appendTo('body');
}
var from_offset;
if (fromCoords instanceof $) {
$el = fromCoords;
var offset = $el.offset();
from_offset = {
left: offset.left + ($el.width() / 2),
top: offset.top + ($el.height() / 2)
};
} else {
$el = this.gridster.gridmap[fromCoords[0]][fromCoords[1]];
from_offset = getMousePos(fromCoords);
}
if (! $el) {
return;
}
var to_offset = getMousePos(toCoords);
var el = $el.get(0);
addPoint(from_offset);
addPoint(to_offset);
// Simulating drag start
var type = 'mousedown';
var event = u.createEvent(type, from_offset);
u.dispatchEvent(el, type, event);
// Simulating drop
type = 'mousemove';
u.dispatchEvent(el, type, u.createEvent(type, {
top: from_offset.top + 2,
left: from_offset.left + 2
}));
this.gridster.$el.on('gridster:dragstop gridster:resizestop', function() {
setTimeout(function() {
d.resolveWith(this);
}.bind(this), SPEED);
}.bind(this));
var diff_x = to_offset.left - from_offset.left;
var diff_y = to_offset.top - from_offset.top;
var steps = 10;
var step_x = diff_x / steps;
var step_y = diff_y / steps;
var tmp_offset = {
left: from_offset.left,
top: from_offset.top
};
for (var i = 0; i < steps; i++) {
tmp_offset.left += step_x;
tmp_offset.top += step_y;
addPoint(tmp_offset);
u.dispatchEvent(el, type, u.createEvent(type, tmp_offset));
}
u.dispatchEvent(el, type, u.createEvent(type, to_offset));
addPoint(to_offset);
// Simulating drag end
type = 'mouseup';
var dragEndEvent = u.createEvent(type, to_offset);
u.dispatchEvent(el, type, dragEndEvent);
return d.promise();
}
};

View File

@@ -0,0 +1,27 @@
'use strict';
define([
'QUnit',
'jquery',
'gridster'
], function(QUnit, $, gridster) {
QUnit.module('Gridster AMD', {
setup: function () {
},
teardown: function () {
}
});
QUnit.test('window.$ should be undefined.', function() {
equal(typeof window.$, 'undefined', 'window.$ should be undefined');
equal(typeof window.jQuery, 'undefined', 'window.jQuery should be undefined');
});
QUnit.test('gridster should be initialized.', function() {
$('.wrapper ul').gridster();
equal($('.wrapper').hasClass('ready'), true, 'Gridster should initialized wrapper.');
equal($('.wrapper ul li').length, $('.gs-w').length, 'grid elements get a .gs-w class');
});
}
);

View File

@@ -0,0 +1,840 @@
<?php
/*********************************************************************
*
* Pure PHP radius class
*
* This Radius class is a radius client implementation in pure PHP
* following the RFC 2865 rules (http://www.ietf.org/rfc/rfc2865.txt)
*
* This class works with at least the following RADIUS servers:
* - Authenex Strong Authentication System (ASAS) with two-factor authentication
* - FreeRADIUS, a free Radius server implementation for Linux and *nix environments
* - Microsoft Radius server IAS
* - Mideye RADIUS server (http://www.mideye.com)
* - Radl, a free Radius server for Windows
* - RSA SecurID
* - VASCO Middleware 3.0 server
* - WinRadius, Windows Radius server (free for 5 users)
* - ZyXEL ZyWALL OTP (Authenex ASAS branded by ZyXEL, cheaper)
*
*
* LICENCE
*
* Copyright (c) 2008, SysCo systemes de communication sa
* SysCo (tm) is a trademark of SysCo systemes de communication sa
* (http://www.sysco.ch/)
* All rights reserved.
*
* This file is part of the Pure PHP radius class
*
* Pure PHP radius class is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Pure PHP radius class is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Pure PHP radius class.
* If not, see <http://www.gnu.org/licenses/>.
*
*
* @author: SysCo/al
* @since CreationDate: 2008-01-04
* @copyright (c) 2008 by SysCo systemes de communication sa
* @version $LastChangedRevision: 1.2.2 $
* @version $LastChangedDate: 2009-01-05 $
* @version $LastChangedBy: SysCo/al $
* @link $HeadURL: radius.class.php $
* @link http://developer.sysco.ch/php/
* @link developer@sysco.ch
* Language: PHP 4.0.7 or higher
*
*
* Usage
*
* require_once('radius.class.php');
* $radius = new Radius($ip_radius_server = 'radius_server_ip_address', $shared_secret = 'radius_shared_secret'[, $radius_suffix = 'optional_radius_suffix'[, $udp_timeout = udp_timeout_in_seconds[, $authentication_port = 1812]]]);
* $result = $radius->Access_Request($username = 'username', $password = 'password'[, $udp_timeout = udp_timeout_in_seconds]);
*
*
* Examples
*
* Example 1
* <?php
* require_once('radius.class.php');
* $radius = new Radius('127.0.0.1', 'secret');
* $radius->SetNasIpAddress('1.2.3.4'); // Needed for some devices, and not auto_detected if PHP not runned through a web server
* if ($radius->AccessRequest('user', 'pass'))
* {
* echo "Authentication accepted.";
* }
* else
* {
* echo "Authentication rejected.";
* }
* ?>
*
* Example 2
* <?php
* require_once('radius.class.php');
* $radius = new Radius('127.0.0.1', 'secret');
* $radius->SetNasPort(0);
* $radius->SetNasIpAddress('1.2.3.4'); // Needed for some devices, and not auto_detected if PHP not runned through a web server
* if ($radius->AccessRequest('user', 'pass'))
* {
* echo "Authentication accepted.";
* echo "<br />";
* }
* else
* {
* echo "Authentication rejected.";
* echo "<br />";
* }
* echo $radius->GetReadableReceivedAttributes();
* ?>
*
*
* External file needed
*
* none.
*
*
* External file created
*
* none.
*
*
* Special issues
*
* - Sockets support must be enabled.
* * In Linux and *nix environments, the extension is enabled at
* compile time using the --enable-sockets configure option
* * In Windows, PHP Sockets can be activated by un-commenting
* extension=php_sockets.dll in php.ini
*
*
* Other related ressources
*
* FreeRADIUS, a free Radius server implementation for Linux and *nix environments:
* http://www.freeradius.org/
*
* WinRadius, Windows Radius server (free for 5 users):
* http://www.itconsult2000.com/en/product/WinRadius.zip
*
* Radl, a free Radius server for Windows:
* http://www.loriotpro.com/Products/RadiusServer/FreeRadiusServer_EN.php
*
* DOS command line Radius client:
* http://www.itconsult2000.com/en/product/WinRadiusClient.zip
*
*
* Users feedbacks and comments
*
* 2008-07-02 Pim Koeman/Parantion
*
* When using a radius connection behind a linux iptables firewall
* allow port 1812 and 1813 with udp protocol
*
* IPTABLES EXAMPLE (command line):
* iptables -A AlwaysACCEPT -p udp --dport 1812 -j ACCEPT
* iptables -A AlwaysACCEPT -p udp --dport 1813 -j ACCEPT
*
* or put the lines in /etc/sysconfig/iptables (red-hat type systems (fedora, centos, rhel etc.)
* -A AlwaysACCEPT -p udp --dport 1812 -j ACCEPT
* -A AlwaysACCEPT -p udp --dport 1813 -j ACCEPT
*
*
* Change Log
*
* 2009-01-05 1.2.2 SysCo/al Added Robert Svensson feedback, Mideye RADIUS server is supported
* 2008-11-11 1.2.1 SysCo/al Added Carlo Ferrari resolution in examples (add NAS IP Address for a VASCO Middleware server)
* 2008-07-07 1.2 SysCo/al Added Pim Koeman (Parantion) contribution
* - comments concerning using radius behind a linux iptables firewall
* Added Jon Bright (tick Trading Software AG) contribution
* - false octal encoding with 0xx indexes (indexes are now rewritten in xx only)
* - challenge/response support for the RSA SecurID New-PIN mode
* Added GetRadiusPacketInfo() method
* Added GetAttributesInfo() method
* Added DecodeVendorSpecificContent() (to answer Raul Carvalho's question)
* Added Decoded Vendor Specific Content in debug messages
* 2008-02-04 1.1 SysCo/al Typo error for the udp_timeout parameter (line 256 in the version 1.0)
* 2008-01-07 1.0 SysCo/al Initial release
*
*********************************************************************/
/*********************************************************************
*
* Radius
* Pure PHP radius class
*
* Creation 2008-01-04
* Update 2009-01-05
* @package radius
* @version v.1.2.2
* @author SysCo/al
*
*********************************************************************/
class Radius
{
var $_ip_radius_server; // Radius server IP address
var $_shared_secret; // Shared secret with the radius server
var $_radius_suffix; // Radius suffix (default is '');
var $_udp_timeout; // Timeout of the UDP connection in seconds (default value is 5)
var $_authentication_port; // Authentication port (default value is 1812)
var $_accounting_port; // Accouting port (default value is 1813)
var $_nas_ip_address; // NAS IP address
var $_nas_port; // NAS port
var $_encrypted_password; // Encrypted password, as described in the RFC 2865
var $_user_ip_address; // Remote IP address of the user
var $_request_authenticator; // Request-Authenticator, 16 octets random number
var $_response_authenticator; // Request-Authenticator, 16 octets random number
var $_username; // Username to sent to the Radius server
var $_password; // Password to sent to the Radius server (clear password, must be encrypted)
var $_identifier_to_send; // Identifier field for the packet to be sent
var $_identifier_received; // Identifier field for the received packet
var $_radius_packet_to_send; // Radius packet code (1=Access-Request, 2=Access-Accept, 3=Access-Reject, 4=Accounting-Request, 5=Accounting-Response, 11=Access-Challenge, 12=Status-Server (experimental), 13=Status-Client (experimental), 255=Reserved
var $_radius_packet_received; // Radius packet code (1=Access-Request, 2=Access-Accept, 3=Access-Reject, 4=Accounting-Request, 5=Accounting-Response, 11=Access-Challenge, 12=Status-Server (experimental), 13=Status-Client (experimental), 255=Reserved
var $_attributes_to_send; // Radius attributes to send
var $_attributes_received; // Radius attributes received
var $_socket_to_server; // Socket connection
var $_debug_mode; // Debug mode flag
var $_attributes_info; // Attributes info array
var $_radius_packet_info; // Radius packet codes info array
var $_last_error_code; // Last error code
var $_last_error_message; // Last error message
/*********************************************************************
*
* Name: Radius
* short description: Radius class constructor
*
* Creation 2008-01-04
* Update 2009-01-05
* @version v.1.2.2
* @author SysCo/al
* @param string ip address of the radius server
* @param string shared secret with the radius server
* @param string radius domain name suffix (default is empty)
* @param integer UDP timeout (default is 5)
* @param integer authentication port
* @param integer accounting port
* @return NULL
*********************************************************************/
public function Radius($ip_radius_server = '127.0.0.1', $shared_secret = '', $radius_suffix = '', $udp_timeout = 5, $authentication_port = 1812, $accounting_port = 1813)
{
$this->_radius_packet_info[1] = 'Access-Request';
$this->_radius_packet_info[2] = 'Access-Accept';
$this->_radius_packet_info[3] = 'Access-Reject';
$this->_radius_packet_info[4] = 'Accounting-Request';
$this->_radius_packet_info[5] = 'Accounting-Response';
$this->_radius_packet_info[11] = 'Access-Challenge';
$this->_radius_packet_info[12] = 'Status-Server (experimental)';
$this->_radius_packet_info[13] = 'Status-Client (experimental)';
$this->_radius_packet_info[255] = 'Reserved';
$this->_attributes_info[1] = array('User-Name', 'S');
$this->_attributes_info[2] = array('User-Password', 'S');
$this->_attributes_info[3] = array('CHAP-Password', 'S'); // Type (1) / Length (1) / CHAP Ident (1) / String
$this->_attributes_info[4] = array('NAS-IP-Address', 'A');
$this->_attributes_info[5] = array('NAS-Port', 'I');
$this->_attributes_info[6] = array('Service-Type', 'I');
$this->_attributes_info[7] = array('Framed-Protocol', 'I');
$this->_attributes_info[8] = array('Framed-IP-Address', 'A');
$this->_attributes_info[9] = array('Framed-IP-Netmask', 'A');
$this->_attributes_info[10] = array('Framed-Routing', 'I');
$this->_attributes_info[11] = array('Filter-Id', 'T');
$this->_attributes_info[12] = array('Framed-MTU', 'I');
$this->_attributes_info[13] = array('Framed-Compression', 'I');
$this->_attributes_info[14] = array( 'Login-IP-Host', 'A');
$this->_attributes_info[15] = array('Login-service', 'I');
$this->_attributes_info[16] = array('Login-TCP-Port', 'I');
$this->_attributes_info[17] = array('(unassigned)', '');
$this->_attributes_info[18] = array('Reply-Message', 'T');
$this->_attributes_info[19] = array('Callback-Number', 'S');
$this->_attributes_info[20] = array('Callback-Id', 'S');
$this->_attributes_info[21] = array('(unassigned)', '');
$this->_attributes_info[22] = array('Framed-Route', 'T');
$this->_attributes_info[23] = array('Framed-IPX-Network', 'I');
$this->_attributes_info[24] = array('State', 'S');
$this->_attributes_info[25] = array('Class', 'S');
$this->_attributes_info[26] = array('Vendor-Specific', 'S'); // Type (1) / Length (1) / Vendor-Id (4) / Vendor type (1) / Vendor length (1) / Attribute-Specific...
$this->_attributes_info[27] = array('Session-Timeout', 'I');
$this->_attributes_info[28] = array('Idle-Timeout', 'I');
$this->_attributes_info[29] = array('Termination-Action', 'I');
$this->_attributes_info[30] = array('Called-Station-Id', 'S');
$this->_attributes_info[31] = array('Calling-Station-Id', 'S');
$this->_attributes_info[32] = array('NAS-Identifier', 'S');
$this->_attributes_info[33] = array('Proxy-State', 'S');
$this->_attributes_info[34] = array('Login-LAT-Service', 'S');
$this->_attributes_info[35] = array('Login-LAT-Node', 'S');
$this->_attributes_info[36] = array('Login-LAT-Group', 'S');
$this->_attributes_info[37] = array('Framed-AppleTalk-Link', 'I');
$this->_attributes_info[38] = array('Framed-AppleTalk-Network', 'I');
$this->_attributes_info[39] = array('Framed-AppleTalk-Zone', 'S');
$this->_attributes_info[60] = array('CHAP-Challenge', 'S');
$this->_attributes_info[61] = array('NAS-Port-Type', 'I');
$this->_attributes_info[62] = array('Port-Limit', 'I');
$this->_attributes_info[63] = array('Login-LAT-Port', 'S');
$this->_attributes_info[76] = array('Prompt', 'I');
$this->_identifier_to_send = 0;
$this->_user_ip_address = (isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:'0.0.0.0');
$this->GenerateRequestAuthenticator();
$this->SetIpRadiusServer($ip_radius_server);
$this->SetSharedSecret($shared_secret);
$this->SetAuthenticationPort($authentication_port);
$this->SetAccountingPort($accounting_port);
$this->SetRadiusSuffix($radius_suffix);
$this->SetUdpTimeout($udp_timeout);
$this->SetUsername();
$this->SetPassword();
$this->SetNasIpAddress();
$this->SetNasPort();
$this->ClearLastError();
$this->ClearDataToSend();
$this->ClearDataReceived();
}
function GetNextIdentifier()
{
$this->_identifier_to_send = (($this->_identifier_to_send + 1) % 256);
return $this->_identifier_to_send;
}
function GenerateRequestAuthenticator()
{
$this->_request_authenticator = '';
for ($ra_loop = 0; $ra_loop <= 15; $ra_loop++)
{
$this->_request_authenticator .= chr(rand(1, 255));
}
}
function GetRequestAuthenticator()
{
return $this->_request_authenticator;
}
function GetLastError()
{
if (0 < $this->_last_error_code)
{
return $this->_last_error_message.' ('.$this->_last_error_code.')';
}
else
{
return '';
}
}
function ClearDataToSend()
{
$this->_radius_packet_to_send = 0;
$this->_attributes_to_send = NULL;
}
function ClearDataReceived()
{
$this->_radius_packet_received = 0;
$this->_attributes_received = NULL;
}
function SetPacketCodeToSend($packet_code)
{
$this->_radius_packet_to_send = $packet_code;
}
function SetDebugMode($debug_mode)
{
$this->_debug_mode = (TRUE === $debug_mode);
}
function SetIpRadiusServer($ip_radius_server)
{
$this->_ip_radius_server = gethostbyname($ip_radius_server);
}
function SetSharedSecret($shared_secret)
{
$this->_shared_secret = $shared_secret;
}
function SetRadiusSuffix($radius_suffix)
{
$this->_radius_suffix = $radius_suffix;
}
function SetUsername($username = '')
{
$temp_username = $username;
if (false === strpos($temp_username, '@'))
{
$temp_username .= $this->_radius_suffix;
}
$this->_username = $temp_username;
$this->SetAttribute(1, $this->_username);
}
function SetPassword($password = '')
{
$this->_password = $password;
$encrypted_password = '';
$padded_password = $password;
if (0 != (strlen($password)%16))
{
$padded_password .= str_repeat(chr(0),(16-strlen($password)%16));
}
$previous_result = $this->_request_authenticator;
for ($full_loop = 0; $full_loop < (strlen($padded_password)/16); $full_loop++)
{
$xor_value = md5($this->_shared_secret.$previous_result);
$previous_result = '';
for ($xor_loop = 0; $xor_loop <= 15; $xor_loop++)
{
$value1 = ord(substr($padded_password, ($full_loop * 16) + $xor_loop, 1));
$value2 = hexdec(substr($xor_value, 2*$xor_loop, 2));
$xor_result = $value1 ^ $value2;
$previous_result .= chr($xor_result);
}
$encrypted_password .= $previous_result;
}
$this->_encrypted_password = $encrypted_password;
$this->SetAttribute(2, $this->_encrypted_password);
}
function SetNasIPAddress($nas_ip_address = '')
{
if (0 < strlen($nas_ip_address))
{
$this->_nas_ip_address = gethostbyname($nas_ip_address);
}
else
{
$this->_nas_ip_address = gethostbyname(isset($_SERVER['SERVER_ADDR'])?$_SERVER['SERVER_ADDR']:'0.0.0.0');
}
$this->SetAttribute(4, $this->_nas_ip_address);
}
function SetNasPort($nas_port = 0)
{
$this->_nas_port = intval($nas_port);
$this->SetAttribute(5, $this->_nas_port);
}
function SetUdpTimeout($udp_timeout = 5)
{
if (intval($udp_timeout) > 0)
{
$this->_udp_timeout = intval($udp_timeout);
}
}
function ClearLastError()
{
$this->_last_error_code = 0;
$this->_last_error_message = '';
}
function SetAuthenticationPort($authentication_port)
{
if ((intval($authentication_port) > 0) && (intval($authentication_port) < 65536))
{
$this->_authentication_port = intval($authentication_port);
}
}
function SetAccountingPort($accounting_port)
{
if ((intval($accounting_port) > 0) && (intval($accounting_port) < 65536))
{
$this->_accounting_port = intval($accounting_port);
}
}
function GetReceivedPacket()
{
return $this->_radius_packet_received;
}
function GetReceivedAttributes()
{
return $this->_attributes_received;
}
function GetReadableReceivedAttributes()
{
$readable_attributes = '';
if (isset($this->_attributes_received))
{
foreach($this->_attributes_received as $one_received_attribute)
{
$attributes_info = $this->GetAttributesInfo($one_received_attribute[0]);
$readable_attributes .= $attributes_info[0].": ";
if (26 == $one_received_attribute[0])
{
$vendor_array = $this->DecodeVendorSpecificContent($one_received_attribute[1]);
foreach($vendor_array as $vendor_one)
{
$readable_attributes .= 'Vendor-Id: '.$vendor_one[0].", Vendor-type: ".$vendor_one[1].", Attribute-specific: ".$vendor_one[2];
}
}
else
{
$readable_attributes .= $one_received_attribute[1];
}
$readable_attributes .= "<br />\n";
}
}
return $readable_attributes;
}
function GetAttribute($attribute_type)
{
$attribute_value = NULL;
foreach($this->_attributes_received as $one_received_attribute)
{
if (intval($attribute_type) == $one_received_attribute[0])
{
$attribute_value = $one_received_attribute[1];
break;
}
}
return $attribute_value;
}
function GetRadiusPacketInfo($info_index)
{
if (isset($this->_radius_packet_info[intval($info_index)]))
{
return $this->_radius_packet_info[intval($info_index)];
}
else
{
return '';
}
}
function GetAttributesInfo($info_index)
{
if (isset($this->_attributes_info[intval($info_index)]))
{
return $this->_attributes_info[intval($info_index)];
}
else
{
return array('','');
}
}
function DebugInfo($debug_info)
{
if ($this->_debug_mode)
{
echo date('Y-m-d H:i:s').' DEBUG: ';
echo $debug_info;
echo '<br />';
flush();
}
}
function SetAttribute($type, $value)
{
$attribute_index = -1;
for ($attributes_loop = 0; $attributes_loop < count($this->_attributes_to_send); $attributes_loop++)
{
if ($type == ord(substr($this->_attributes_to_send[$attributes_loop], 0, 1)))
{
$attribute_index = $attributes_loop;
break;
}
}
$temp_attribute = NULL;
if (isset($this->_attributes_info[$type]))
{
switch ($this->_attributes_info[$type][1])
{
case 'T': // Text, 1-253 octets containing UTF-8 encoded ISO 10646 characters (RFC 2279).
$temp_attribute = chr($type).chr(2+strlen($value)).$value;
break;
case 'S': // String, 1-253 octets containing binary data (values 0 through 255 decimal, inclusive).
$temp_attribute = chr($type).chr(2+strlen($value)).$value;
break;
case 'A': // Address, 32 bit value, most significant octet first.
$ip_array = explode(".", $value);
$temp_attribute = chr($type).chr(6).chr($ip_array[0]).chr($ip_array[1]).chr($ip_array[2]).chr($ip_array[3]);
break;
case 'I': // Integer, 32 bit unsigned value, most significant octet first.
$temp_attribute = chr($type).chr(6).chr(($value/(256*256*256))%256).chr(($value/(256*256))%256).chr(($value/(256))%256).chr($value%256);
break;
case 'D': // Time, 32 bit unsigned value, most significant octet first -- seconds since 00:00:00 UTC, January 1, 1970. (not used in this RFC)
$temp_attribute = NULL;
break;
default:
$temp_attribute = NULL;
}
}
if ($attribute_index > -1)
{
$this->_attributes_to_send[$attribute_index] = $temp_attribute;
$additional_debug = 'Modified';
}
else
{
$this->_attributes_to_send[] = $temp_attribute;
$additional_debug = 'Added';
}
$attribute_info = $this->GetAttributesInfo($type);
$this->DebugInfo($additional_debug.' Attribute '.$type.' ('.$attribute_info[0].'), format '.$attribute_info[1].', value <em>'.$value.'</em>');
}
function DecodeAttribute($attribute_raw_value, $attribute_format)
{
$attribute_value = NULL;
if (isset($this->_attributes_info[$attribute_format]))
{
switch ($this->_attributes_info[$attribute_format][1])
{
case 'T': // Text, 1-253 octets containing UTF-8 encoded ISO 10646 characters (RFC 2279).
$attribute_value = $attribute_raw_value;
break;
case 'S': // String, 1-253 octets containing binary data (values 0 through 255 decimal, inclusive).
$attribute_value = $attribute_raw_value;
break;
case 'A': // Address, 32 bit value, most significant octet first.
$attribute_value = ord(substr($attribute_raw_value, 0, 1)).'.'.ord(substr($attribute_raw_value, 1, 1)).'.'.ord(substr($attribute_raw_value, 2, 1)).'.'.ord(substr($attribute_raw_value, 3, 1));
break;
case 'I': // Integer, 32 bit unsigned value, most significant octet first.
$attribute_value = (ord(substr($attribute_raw_value, 0, 1))*256*256*256)+(ord(substr($attribute_raw_value, 1, 1))*256*256)+(ord(substr($attribute_raw_value, 2, 1))*256)+ord(substr($attribute_raw_value, 3, 1));
break;
case 'D': // Time, 32 bit unsigned value, most significant octet first -- seconds since 00:00:00 UTC, January 1, 1970. (not used in this RFC)
$attribute_value = NULL;
break;
default:
$attribute_value = NULL;
}
}
return $attribute_value;
}
/*********************************************************************
* Array returned: array(array(Vendor-Id1, Vendor type1, Attribute-Specific1), ..., array(Vendor-IdN, Vendor typeN, Attribute-SpecificN)
*********************************************************************/
function DecodeVendorSpecificContent($vendor_specific_raw_value)
{
$result = array();
$offset_in_raw = 0;
$vendor_id = (ord(substr($vendor_specific_raw_value, 0, 1))*256*256*256)+(ord(substr($vendor_specific_raw_value, 1, 1))*256*256)+(ord(substr($vendor_specific_raw_value, 2, 1))*256)+ord(substr($vendor_specific_raw_value, 3, 1));
$offset_in_raw += 4;
while ($offset_in_raw < strlen($vendor_specific_raw_value))
{
$vendor_type = (ord(substr($vendor_specific_raw_value, 0+$offset_in_raw, 1)));
$vendor_length = (ord(substr($vendor_specific_raw_value, 1+$offset_in_raw, 1)));
$attribute_specific = substr($vendor_specific_raw_value, 2+$offset_in_raw, $vendor_length);
$result[] = array($vendor_id, $vendor_type, $attribute_specific);
$offset_in_raw += ($vendor_length);
}
return $result;
}
/*
* Function : AccessRequest
*
* Return TRUE if Access-Request is accepted, FALSE otherwise
*/
function AccessRequest($username = '', $password = '', $udp_timeout = 0, $state = NULL)
{
$this->ClearDataReceived();
$this->ClearLastError();
$this->SetPacketCodeToSend(1); // Access-Request
if (0 < strlen($username))
{
$this->SetUsername($username);
}
if (0 < strlen($password))
{
$this->SetPassword($password);
}
if ($state!==NULL)
{
$this->SetAttribute(24, $state);
}
else
{
$this->SetAttribute(6, 1); // 1=Login
}
if (intval($udp_timeout) > 0)
{
$this->SetUdpTimeout($udp_timeout);
}
$attributes_content = '';
for ($attributes_loop = 0; $attributes_loop < count($this->_attributes_to_send); $attributes_loop++)
{
$attributes_content .= $this->_attributes_to_send[$attributes_loop];
}
$packet_length = 4; // Radius packet code + Identifier + Length high + Length low
$packet_length += strlen($this->_request_authenticator); // Request-Authenticator
$packet_length += strlen($attributes_content); // Attributes
$packet_data = chr($this->_radius_packet_to_send);
$packet_data .= chr($this->GetNextIdentifier());
$packet_data .= chr(intval($packet_length/256));
$packet_data .= chr(intval($packet_length%256));
$packet_data .= $this->_request_authenticator;
$packet_data .= $attributes_content;
$_socket_to_server = socket_create(AF_INET, SOCK_DGRAM, 17); // UDP packet = 17
if ($_socket_to_server === FALSE)
{
$this->_last_error_code = socket_last_error();
$this->_last_error_message = socket_strerror($this->_last_error_code);
}
elseif (FALSE === socket_connect($_socket_to_server, $this->_ip_radius_server, $this->_authentication_port))
{
$this->_last_error_code = socket_last_error();
$this->_last_error_message = socket_strerror($this->_last_error_code);
}
elseif (FALSE === socket_write($_socket_to_server, $packet_data, $packet_length))
{
$this->_last_error_code = socket_last_error();
$this->_last_error_message = socket_strerror($this->_last_error_code);
}
else
{
$this->DebugInfo('<b>Packet type '.$this->_radius_packet_to_send.' ('.$this->GetRadiusPacketInfo($this->_radius_packet_to_send).')'.' sent</b>');
if ($this->_debug_mode)
{
$readable_attributes = '';
foreach($this->_attributes_to_send as $one_attribute_to_send)
{
$attribute_info = $this->GetAttributesInfo(ord(substr($one_attribute_to_send,0,1)));
$this->DebugInfo('Attribute '.ord(substr($one_attribute_to_send,0,1)).' ('.$attribute_info[0].'), length '.(ord(substr($one_attribute_to_send,1,1))-2).', format '.$attribute_info[1].', value <em>'.$this->DecodeAttribute(substr($one_attribute_to_send,2), ord(substr($one_attribute_to_send,0,1))).'</em>');
}
}
$read_socket_array = array($_socket_to_server);
$write_socket_array = NULL;
$except_socket_array = NULL;
$received_packet = chr(0);
if (!(FALSE === socket_select($read_socket_array, $write_socket_array, $except_socket_array, $this->_udp_timeout)))
{
if (in_array($_socket_to_server, $read_socket_array))
{
if (FALSE === ($received_packet = @socket_read($_socket_to_server, 1024))) // @ used, than no error is displayed if the connection is closed by the remote host
{
$received_packet = chr(0);
$this->_last_error_code = socket_last_error();
$this->_last_error_message = socket_strerror($this->_last_error_code);
}
else
{
socket_close($_socket_to_server);
}
}
}
else
{
socket_close($_socket_to_server);
}
}
$this->_radius_packet_received = intval(ord(substr($received_packet, 0, 1)));
$this->DebugInfo('<b>Packet type '.$this->_radius_packet_received.' ('.$this->GetRadiusPacketInfo($this->_radius_packet_received).')'.' received</b>');
if ($this->_radius_packet_received > 0)
{
$this->_identifier_received = intval(ord(substr($received_packet, 1, 1)));
$packet_length = (intval(ord(substr($received_packet, 2, 1))) * 256) + (intval(ord(substr($received_packet, 3, 1))));
$this->_response_authenticator = substr($received_packet, 4, 16);
$attributes_content = substr($received_packet, 20, ($packet_length - 4 - 16));
while (strlen($attributes_content) > 2)
{
$attribute_type = intval(ord(substr($attributes_content,0,1)));
$attribute_length = intval(ord(substr($attributes_content,1,1)));
$attribute_raw_value = substr($attributes_content,2,$attribute_length-2);
$attributes_content = substr($attributes_content, $attribute_length);
$attribute_value = $this->DecodeAttribute($attribute_raw_value, $attribute_type);
$attribute_info = $this->GetAttributesInfo($attribute_type);
if (26 == $attribute_type)
{
$vendor_array = $this->DecodeVendorSpecificContent($attribute_value);
foreach($vendor_array as $vendor_one)
{
$this->DebugInfo('Attribute '.$attribute_type.' ('.$attribute_info[0].'), length '.($attribute_length-2).', format '.$attribute_info[1].', Vendor-Id: '.$vendor_one[0].", Vendor-type: ".$vendor_one[1].", Attribute-specific: ".$vendor_one[2]);
}
}
else
{
$this->DebugInfo('Attribute '.$attribute_type.' ('.$attribute_info[0].'), length '.($attribute_length-2).', format '.$attribute_info[1].', value <em>'.$attribute_value.'</em>');
}
$this->_attributes_received[] = array($attribute_type, $attribute_value);
}
}
return (2 == ($this->_radius_packet_received));
}
}
?>