123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- /*
- The MIT License (MIT)
- Copyright (c) 2013 [email protected]
- 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.
- */
- ;(function( $, window, document, undefined ){
- var pluginName = 'wickedtoolbar';
- var SHIFT = new RegExp(/shift/i);
- var ALT = new RegExp(/alt/i);
- var CTRL = new RegExp(/ctrl/i);
- var ARROW_DOWN = new RegExp(/↓/);
- var ARROW_UP = new RegExp(/↑/);
- var ARROW_LEFT = new RegExp(/←/);
- var ARROW_RIGHT = new RegExp(/→/);
-
- var keys = {
- shift: 16,
- alt: 17,
- ctrl: 18,
- meta: 91,
- arrow_up: 38,
- arrow_down: 40,
- arrow_left: 37,
- arrow_right: 39
- };
- var defaults = {
- hasIcon: function(id) { },
- getIcon: function(id) { }
- };
-
- function MenuBase(element, options) {
- var self = this;
-
- this.element = $(element);
- this.settings = $.extend({}, defaults, options);
- this.bindings = [];
- // for each menu item, modify and wrap in div
- this.element.find('li').each(function () {
- var tthis = $(this);
-
- // since the DOM is modifying wrt to icons, it can match the li[data-cion] from
- // the HTML definition, or the span.icon from the modified DOM
- var icons = tthis.closest('ul').find('li[data-icon], span.icon').length > 0;
-
- var tnode = tthis.contents().filter(function() { return this.nodeType == 3; }).first();
- var text = tnode.text().trim();
-
- // remove the text node
- tnode.remove();
-
- if (!text || !text.length) return; // not a regular menu item
-
- // change: <li>Text</li>
- // to: <li>
- // <a>
- // <span>Text</span>
- // </a>
- // </li>
- var li = tthis;
- var div = $('<a class="menu-item" href="#">');
- div.click(function(ev) {
- $(this).focus();
- // li.id > a
- var id = $(this).parent().attr('id');
- if (id) {
- self.element.trigger('selected', [id]);
- $(this).parents('.hover').removeClass('hover');
- }
- return false;
- });
-
- var span;
- if (self.settings._type == 'menu') {
- span = $('<span>' + text + '</span>');
- }
- else {
- span = $('<span></span>');
- }
- div.append(span);
-
- if (self.settings._type == 'menu') {
- // accesskey
- var accesskey = tthis.attr('accesskey');
- if (accesskey) {
- div.attr('accesskey', accesskey);
- tthis.removeAttr('accesskey');
- }
-
- // hotkey
- var hotkey = tthis.attr('data-hotkey');
- if (hotkey) {
- tthis.removeAttr('data-hotkey');
- div.append('<span class="hotkey">' + hotkey + '</span>');
- if (!accesskey) {
- // add our own handler
- var parts = hotkey.split('+');
- var bind = {};
- for (var i = 0; i < parts.length; ++i) {
- if (SHIFT.test(parts[i])) {
- bind.shiftKey = true;
- }
- else if (ALT.test(parts[i])) {
- bind.altKey = true;
- }
- else if (CTRL.test(parts[i])) {
- bind.ctrlKey = true;
- }
- else if (ARROW_DOWN.test(parts[i])) {
- bind.which = keys.arrow_down;
- }
- else if (ARROW_UP.test(parts[i])) {
- bind.which = keys.arrow_up;
- }
- else if (ARROW_RIGHT.test(parts[i])) {
- bind.which = keys.arrow_right;
- }
- else if (ARROW_LEFT.test(parts[i])) {
- bind.which = keys.arrow_left;
- }
- }
- bind.target = div;
- self.bindings.push(bind);
- }
- }
- }
-
- // icon
- var id = tthis.attr('id'), icon;
- if (self.settings.hasIcon(id)) {
- span.addClass('icon');
- icon = self.settings.getIcon(id);
- if (icon) {
- span.addClass(icon);
- }
- }
- icon = tthis.attr('data-icon');
- if (icon) {
- tthis.removeAttr('data-icon');
- span.addClass('icon ' + icon);
- }
- else if (icons) {
- span.addClass('icon');
- }
- li.prepend(div);
- });
- $(document).on('keydown', function(ev) {
- for (var i = 0; i < self.bindings.length; ++i) {
- var bind = self.bindings[i];
- // handle custom key events
- if ((bind.shiftKey === undefined ? true : (bind.shiftKey === ev.shiftKey)) &&
- (bind.ctrlKey === undefined ? true : (bind.ctrlKey === ev.ctrlKey)) &&
- (bind.altKey === undefined ? true : (bind.altKey === ev.altKey)) &&
- bind.which && ev.which && (bind.which === ev.which)) {
- bind.target.trigger('click');
- ev.preventDefault();
- }
- }
- });
- }
-
- MenuBase.prototype.update = function (id) {
- var li = this.element.find('#' + id), icon;
- var span = li.find('span:first-child');
- if (this.settings.hasIcon(id)) {
- span.removeClass(); // this could be brutally unfair
- span.addClass('icon');
- icon = this.settings.getIcon(id);
- if (icon) {
- span.addClass(icon);
- }
- }
- };
-
- // ------------
- // Menu
- // ------------
- function Menu(element, options) {
- options._type = 'menu';
- $.extend(this, new MenuBase(element, options)) ;
- this.constructor();
- }
- Menu.prototype.constructor = function () {
- this.element.addClass('wicked-ui wicked-menu');
- var self = this;
- var dohover = function(ev) {
- $(this).parent().addClass('hover');
- if ($(this).closest('ul').hasClass('wicked-menu')) {
- // if the closest ul is a 'menu' (i.e. if this item is a top-level menu), then
- // aply focus
- $(this).focus();
- }
- if (!self.accessing) {
- // Set 'accessing' to true and one document click to cancel it
- self.accessing = true;
- $(document).one('click', function() {
- if (!self.accessing) return;
- self.accessing = false;
- self.element.find('.hover').removeClass('hover');
- });
- }
- };
-
- this.element.find('> li > a.menu-item').click(dohover);
-
- this.element.find('> li > ul > li ul.drop-menu').each(function() {
- // li > a + ul
- $(this).prev('a.menu-item').addClass('icon-arrow-right');
-
- $(this).prev('a.menu-item').hover(dohover);
- $(this).prev('a.menu-item').mouseleave(
- function() {
- $(this).parent().removeClass('hover');
- }
- );
- });
- this.element.find('> li > a.menu-item').hover(
- function() {
- if (!self.accessing) return;
- self.element.find('.hover').removeClass('hover');
- $.proxy(dohover, this)();
- }
- );
- };
-
- // ------------
- // Toolbar
- // ------------
- function Toolbar(element, options) {
- options._type = 'toolbar';
- $.extend(this, new MenuBase(element, options)) ;
- this.constructor();
- }
-
- Toolbar.prototype.constructor = function () {
- this.element.addClass('wicked-ui wicked-toolbar');
- this.element.find('> li > a.menu-item').hover(
- function(){ $(this).parent().addClass('hover'); },
- function(){ $(this).parent().removeClass('hover'); }
- );
- };
- var plugins = { wickedmenu: Menu, wickedtoolbar: Toolbar };
- for (var key in plugins) {
- (function(name, Plugin){
- $.fn[name] = function (options) {
- var args = arguments;
- return this.each(function () {
- if (typeof options === 'object' || !options) {
- if (!$.data(this, 'plugin_' + name)) {
- $.data(this, 'plugin_' + name, new Plugin( this, options ));
- }
- }
- else {
- var d = $.data(this, 'plugin_' + name);
- if (!d) {
- $.error('jQuery.' + name + ' plugin does not exist');
- return;
- }
- return d[options](Array.prototype.slice.call(args, 1));
- }
- });
- };
- })(key, plugins[key])
- }
-
- })( jQuery, window, document );
|