diff --git a/css/bootstrap-magic-button.css b/css/bootstrap-magic-button.css
new file mode 100644
index 0000000..5bf51b0
--- /dev/null
+++ b/css/bootstrap-magic-button.css
@@ -0,0 +1,21 @@
+button[class^=magicBtn] {
+ display: none;
+ position: fixed;
+ border-style: none;
+ background: none;
+ background-repeat: no-repeat;
+ width: 47px;
+ height: 32px;
+ opacity: 0.7;
+}
+
+button[class*="magicBtn-active"] {
+ position: fixed;
+ border-style: none;
+ background: none;
+ background-repeat: no-repeat;
+ width: 47px;
+ height: 32px;
+ opacity: 1;
+}
+
diff --git a/example.html b/example.html
index 30db750..f8445a3 100644
--- a/example.html
+++ b/example.html
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
+
@@ -15,9 +15,9 @@
test adsgdsgds
-
-
-
+
+
+
@@ -30,8 +30,8 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
What is it?
+
+
It's a plugin that let's you make buttons that stick on the borders of any div
+
+
+
+
+
Example
+
+
+
+
This is the most basic magic button, the default behavior is to stick on the right side
+ of div which is containing magic buttons
+
+
+
+
+
+
+
Code:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/img/magicBtn-msg.png b/img/magicBtn-msg.png
new file mode 100644
index 0000000..6710761
Binary files /dev/null and b/img/magicBtn-msg.png differ
diff --git a/img/magicBtn-pin-off.png b/img/magicBtn-pin-off.png
new file mode 100644
index 0000000..0718371
Binary files /dev/null and b/img/magicBtn-pin-off.png differ
diff --git a/img/magicBtn-pin-on.png b/img/magicBtn-pin-on.png
new file mode 100644
index 0000000..6cb169d
Binary files /dev/null and b/img/magicBtn-pin-on.png differ
diff --git a/js/bootstrap-magic-button.js b/js/bootstrap-magic-button.js
new file mode 100644
index 0000000..346a317
--- /dev/null
+++ b/js/bootstrap-magic-button.js
@@ -0,0 +1,208 @@
+/* ============================================================
+ * bootstrap-magic-button.js v1.0
+ * https://github.com/sp4ke/bootstrap-magic-button
+ * ============================================================
+ * Copyright 2012 Chakib Benziane
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Modified work : bootstrap-button.js v2.0.2
+ * Copyright 2012 Twitter, Inc.
+ * ============================================================ */!
+function ($) {
+
+ "use strict"
+
+ /* BUTTON PUBLIC CLASS DEFINITION
+ * ============================== */
+
+ var MagicBtn = function (element, options) {
+ this.$element = $(element)
+
+ // The parent Div
+ this.$parentDiv = $(element).closest('div')
+ this.$parentHeight = this.$parentDiv.outerHeight()
+ this.$parentWidth = this.$parentDiv.outerWidth()
+ this.$parentPosition = this.$parentDiv.position();
+ this.$parentMarginLeft = this.$parentDiv.css('margin-left')
+ this.options = $.extend({}, $.fn.magicBtn.defaults, options)
+
+ // Store number of buttons on parent div
+ if (!this.$parentDiv.data('nbMagicBtns')) this.$parentDiv.data('nbMagicBtns', 1)
+ else this.$parentDiv.data().nbMagicBtns++;
+
+ // Store the current button number
+ this.$currentBtnNb = this.$parentDiv.data('nbMagicBtns')
+
+ // store the currunt button size
+ this.$height = this.$element.outerHeight() + this.options.betweenSpace / 2
+ this.$width = this.$element.outerWidth()
+
+ // current button image and toggle image if there is
+ this.$imgUrl = 'url("' + this.$element.data('image') + '")'
+ var toggleimg
+ if (toggleimg = this.$element.data('toggle-image')) this.$toggleImgUrl = 'url("' + toggleimg + '")'
+ else this.$toggleImgUrl = this.$imgUrl
+
+ this.$isToggled = false
+
+ if (this.options.hover) this.addHover()
+ }
+
+ MagicBtn.prototype = {
+
+ constructor: MagicBtn
+
+ // state is the option recieved from jQuery plugin
+ ,
+ setState: function (state) {
+ var d = 'disabled',
+ $el = this.$element,
+ data = $el.data(),
+ val = $el.is('input') ? 'val' : 'html'
+
+ state = state + 'Text'
+ data.resetText || $el.data('resetText', $el[val]())
+
+ $el[val](data[state] || this.options[state])
+
+ // push to event loop to allow forms to submit
+ setTimeout(function () {
+ state == 'loadingText' ? $el.addClass(d).attr(d, d) : $el.removeClass(d).removeAttr(d)
+ }, 0)
+ }
+
+ ,
+ calculatePosition: function (direction) {
+ var space = (this.$currentBtnNb === 1) ? 0 : this.options.betweenSpace
+ var left = this.$parentPosition.left + this.$parentWidth
+ switch (this.options.alignement) {
+ case 'top':
+ this.$top = (
+ (this.$currentBtnNb * this.$height) - this.$height + this.$parentPosition.top + (space * (this.$currentBtnNb - 1)))
+ break;
+ case 'center':
+
+ if (this.$currentBtnNb === 1) {
+ this.$top = (
+ (this.$parentHeight / 2) - (this.$height / 2) + this.$parentPosition.top)
+ this.$parentDiv.data('top-space', (this.$parentHeight / 2 - (this.$height / 2)))
+ this.$parentDiv.data('bottom-space', (this.$parentHeight / 2 - (this.$height / 2)))
+ } else if (this.$currentBtnNb % 2 === 0) {
+ this.$top = (
+ this.$parentDiv.data('top-space') - this.$height + this.$parentPosition.top)
+ this.$parentDiv.data('top-space', this.$parentDiv.data('top-space') - this.$height)
+ } else {
+ this.$top = (
+ this.$parentHeight - this.$parentDiv.data('bottom-space') + this.$parentPosition.top)
+
+ this.$parentDiv.data('bottom-space', this.$parentDiv.data('bottom-space') - this.$height)
+ }
+ break;
+
+
+
+ }
+ this.$left = this.$parentPosition.left + this.$parentWidth + parseInt(this.$parentMarginLeft)
+ }
+
+ ,
+ show: function () {
+ var $o = this.options
+ this.$element.css({
+ top: this.$top,
+ left: this.$left,
+ 'background-image': this.$imgUrl
+ }).show()
+ }
+
+ ,
+ hide: function () {
+ this.$element.hide()
+ }
+
+ ,
+ toggle: function () {
+ var $el = this.$element
+ if (!this.$isToggled) {
+ $el.css('background-image', this.$toggleImgUrl)
+ this.$isToggled = true
+ $el.addClass('magicBtn-active')
+ } else {
+ $el.css('background-image', this.$imgUrl)
+ this.$isToggled = false
+ $el.removeClass('magicBtn-active')
+ }
+ }
+
+ ,
+ addHover: function () {
+ var $el = this.$element
+ var obj = this
+ var config = {
+ over: function () {
+ if (!obj.$isToggled) $(this).toggleClass('magicBtn-active')
+ },
+ timeout: 1,
+ out: function () {
+ if ((!obj.$isToggled) && (!$el.is(':hover')) && ($el.hasClass('magicBtn-active'))) $(this).toggleClass('magicBtn-active', 100)
+ }
+ }
+ $el.hoverIntent(config)
+
+ }
+
+ }
+
+
+ /* BUTTON PLUGIN DEFINITION
+ * ======================== */
+
+ $.fn.magicBtn = function (option) {
+ return this.each(function () {
+ var $this = $(this),
+ data = $this.data('magicBtn'),
+ options = typeof option == 'object' && option
+ if (!data) $this.data('magicBtn', (data = new MagicBtn(this, options)))
+ data.calculatePosition('right')
+ if (option == 'toggle') data.toggle()
+ if (option == 'show') data.show()
+ if (option == 'hide') data.hide()
+ else if (option) data.setState(option)
+
+ })
+ }
+
+ $.fn.magicBtn.defaults = {
+ loadingText: 'loading...',
+ direction: 'right',
+ betweenSpace: 2,
+ alignement: 'center',
+ hover: false
+ }
+
+ $.fn.magicBtn.Constructor = MagicBtn
+
+
+ /* BUTTON DATA-API
+ * =============== */
+
+ $(function () {
+ $('body').on('click.magicBtn.data-api', '[data-toggle^=magicBtn]', function (e) {
+ var $btn = $(e.target)
+ if (!$btn.hasClass('magicBtn')) $btn = $btn.closest('.magicBtn')
+ $btn.magicBtn('toggle')
+ })
+ })
+
+}(window.jQuery);
\ No newline at end of file
diff --git a/js/jquery.hoverIntent.js b/js/jquery.hoverIntent.js
new file mode 100644
index 0000000..3dcff26
--- /dev/null
+++ b/js/jquery.hoverIntent.js
@@ -0,0 +1,106 @@
+/**
+* hoverIntent is similar to jQuery's built-in "hover" function except that
+* instead of firing the onMouseOver event immediately, hoverIntent checks
+* to see if the user's mouse has slowed down (beneath the sensitivity
+* threshold) before firing the onMouseOver event.
+*
+* hoverIntent r6 // 2011.02.26 // jQuery 1.5.1+
+*
+*
+* hoverIntent is currently available for use in all personal or commercial
+* projects under both MIT and GPL licenses. This means that you can choose
+* the license that best suits your project, and use it accordingly.
+*
+* // basic usage (just like .hover) receives onMouseOver and onMouseOut functions
+* $("ul li").hoverIntent( showNav , hideNav );
+*
+* // advanced usage receives configuration object only
+* $("ul li").hoverIntent({
+* sensitivity: 7, // number = sensitivity threshold (must be 1 or higher)
+* interval: 100, // number = milliseconds of polling interval
+* over: showNav, // function = onMouseOver callback (required)
+* timeout: 0, // number = milliseconds delay before onMouseOut function call
+* out: hideNav // function = onMouseOut callback (required)
+* });
+*
+* @param f onMouseOver function || An object with configuration options
+* @param g onMouseOut function || Nothing (use configuration options object)
+* @author Brian Cherne brian(at)cherne(dot)net
+*/
+(function($) {
+ $.fn.hoverIntent = function(f,g) {
+ // default configuration options
+ var cfg = {
+ sensitivity: 7,
+ interval: 100,
+ timeout: 0
+ };
+ // override configuration options with user supplied object
+ cfg = $.extend(cfg, g ? { over: f, out: g } : f );
+
+ // instantiate variables
+ // cX, cY = current X and Y position of mouse, updated by mousemove event
+ // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
+ var cX, cY, pX, pY;
+
+ // A private function for getting mouse position
+ var track = function(ev) {
+ cX = ev.pageX;
+ cY = ev.pageY;
+ };
+
+ // A private function for comparing current and previous mouse position
+ var compare = function(ev,ob) {
+ ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+ // compare mouse positions to see if they've crossed the threshold
+ if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
+ $(ob).unbind("mousemove",track);
+ // set hoverIntent state to true (so mouseOut can be called)
+ ob.hoverIntent_s = 1;
+ return cfg.over.apply(ob,[ev]);
+ } else {
+ // set previous coordinates for next time
+ pX = cX; pY = cY;
+ // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
+ ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
+ }
+ };
+
+ // A private function for delaying the mouseOut function
+ var delay = function(ev,ob) {
+ ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+ ob.hoverIntent_s = 0;
+ return cfg.out.apply(ob,[ev]);
+ };
+
+ // A private function for handling mouse 'hovering'
+ var handleHover = function(e) {
+ // copy objects to be passed into t (required for event object to be passed in IE)
+ var ev = jQuery.extend({},e);
+ var ob = this;
+
+ // cancel hoverIntent timer if it exists
+ if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
+
+ // if e.type == "mouseenter"
+ if (e.type == "mouseenter") {
+ // set "previous" X and Y position based on initial entry point
+ pX = ev.pageX; pY = ev.pageY;
+ // update "current" X and Y position based on mousemove
+ $(ob).bind("mousemove",track);
+ // start polling interval (self-calling timeout) to compare mouse coordinates over time
+ if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
+
+ // else e.type == "mouseleave"
+ } else {
+ // unbind expensive mousemove event
+ $(ob).unbind("mousemove",track);
+ // if hoverIntent state is true, then call the mouseOut function after the specified delay
+ if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
+ }
+ };
+
+ // bind the function to the two event listeners
+ return this.bind('mouseenter',handleHover).bind('mouseleave',handleHover);
+ };
+})(jQuery);
\ No newline at end of file