/* * jqCtxMenu - a jQuery plugin * 1.0-beta * Copyright 2014 * All Rights Reserved. * Use, reproduction, distribution, and modification of this code is subject to the terms and * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php * * Author: hAWK * Repository: https://github.com/hAWKdv/jqCtxMenu */ (function($) { "use strict"; var RMB = 2, CTX_X_OFFSET = 2, CTX_Y_OFFSET = -15, CTX_CONTAINER = "jqctx-container", CTX_CLASS = "jqctx", CTX_SUB_CLASS = "jqctx-sub", CTX_ARROW_CLASS = "jqctx-arrow", name = "name", action = "action", context = {}, $mainContainer = $("#" + CTX_CONTAINER), $currentContainer = $mainContainer, totalCtxWidth = 0, paddingXOffset, $currentMenu, $mainMenu, $subMenu, Queue, menus; // >> Helpers Queue = (function() { function Queue() { this._container = []; } Queue.prototype.isEmpty = function() { return !this._container.length; }; Queue.prototype.length = function() { return this._container.length; }; Queue.prototype.enqueue = function(obj) { this._container.push(obj); }; Queue.prototype.dequeue = function() { return this._container.shift(); }; return Queue; }()); // >> Validation context.isValid = function(prop, i) { if (!this.options[i][prop]) { throw new Error(prop + " is mandatory for context menu object."); } }; // >> On initialization functions context.bindInitialEvent = function() { $(document).mousedown(function() { $mainContainer.find("> ." + CTX_CLASS).hide(); }); }; context.buildInitialContainer = function() { var container; if (!$(CTX_CONTAINER).length) { container = $("
").attr("id", CTX_CONTAINER); $("body").append(container); $mainContainer = $("#" + CTX_CONTAINER); $currentContainer = $mainContainer; this.bindInitialEvent(); } }; // >> Finalization functions context.finalizeSetting = function() { // Sets the sub-menu selector (used for positioning) $subMenu = $("." + CTX_SUB_CLASS + " > ." + CTX_CLASS); // Gets the default option padding paddingXOffset = $("." + CTX_CLASS).find("> li").css("padding-left").replace("px", ""); paddingXOffset = parseInt(paddingXOffset); }; // Determines the longest possible context menu width with all sub-menus opened // BFS-based context.determineTotalWidth = function() { var queue = new Queue(), pathWidths = [], currentWidth, children, currentEl; queue.enqueue({ widthSoFar: 0, menu: $mainMenu }); while (!queue.isEmpty()) { currentEl = queue.dequeue(); children = false; currentWidth = currentEl.widthSoFar + currentEl.menu.width(); currentEl.menu.find("> li > ." + CTX_SUB_CLASS + " > ." + CTX_CLASS) .each(function() { children = true; queue.enqueue({ widthSoFar: currentWidth, menu: $(this) }); }); if (!children) { pathWidths.push(currentWidth); } } totalCtxWidth = Math.max.apply(null, pathWidths); }; // >> Build functions // Creates a new menu container context.buildMenu = function(init) { var menu = $("