⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jquery.mcdropdown.js

📁 Ajax学习的一个经典范例
💻 JS
📖 第 1 页 / 共 3 页
字号:
(function (){
/*!
 * mcDropdown jQuery Plug-in
 *
 * Copyright 2008 Giva, Inc. (http://www.givainc.com/labs/) 
 * 
 * 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.
 *
 * Date: 2008-06-12 
 * Rev:  1.1
 */
	$.fn.mcDropdown = function(list, options) {
		// track the dropdown object
		var dd;

		// create a dropdown for each match
		this.each(function() {
			dd = $.data(this, "mcDropdown");
			// we're already a dropdown, return a reference to myself
			if( dd ) return false;

			new $.mcDropDownMenu(this, list, options);
		});
		
		// return either the dropdown object or the jQuery object reference
		return dd || this;
	};

	// set default options
	$.mcDropdown = {
		version: "1.1",
		setDefaults: function(options){
			$.extend(defaults, options);
		}
	};

	// set the defaults
	var defaults = {
		  minRows: 8                   // specify the minimum rows before creating a new column
		, maxRows: 25                  // specify the maximum rows in a column
		, targetColumnSize: 2          // specify the default target column size (it'll attempt to create this many columns by default, unless the min/max row rules are not being met)
		, openFx: "slideDown"          // the fx to use for showing the root menu
		, openSpeed: 250               // the speed of the openFx
		, closeFx: "slideUp"           // the fx to use for hiding the root menu
		, closeSpeed: 250              // the speed of the closeFx
		, hoverOverDelay: 200          // the delay before opening a submenu
		, hoverOutDelay: 0             // the delay before closing a submenu
		, showFx: "show"               // the fx to use when showing a submenu
		, showSpeed: 0                 // the speed of the showFx
		, hideFx: "hide"               // the fx to use when closing a submenu
		, hideSpeed: 0                 // the speed of the hideFx
		, dropShadow: true             // determine whether drop shadows should be shown on the submenus
		, lineHeight: 19               // the base height of each list item (li) this is normally calculated automatically, but in some cases the value can't be determined and you'll need to set it manually
		, screenPadding: 10            // the padding to use around the border of the screen -- this is used to make sure items stay on the screen
		, allowParentSelect: false     // determines if parent items are allowed to be selected (by default only end nodes can be selected)
		, delim: ":"                   // the delimited to use when showing the display string
		, valueAttr: "rel"             // the attribute that contains the value to use in the hidden field
		, click: null                  // callback that occurs when the user clicks on a menu item
		, select: null                 // callback that occurs when a value is selected
		, init: null                   // callback that occurs when the control is fully initialized
	};

	// check to see if the browser is IE6	
	var isIE6 = ($.browser.version && $.browser.version <= 6);

	$.mcDropDownMenu = function(el, list, options){
		var $self, thismenu = this, $list, $divInput, settings, typedText = "", matchesCache, oldCache, $keylist, $keylistiframe, bInput;
		
		// create a reference to the dropdown
		$self = $(el);
		
		// is the field and input element
		bInput = $self.is(":input");
		
		// get the settings for this instance
		settings = $.extend({}, defaults, options);
		
		// set the default click behavior
		if( settings.click == null ) settings.click = function (e, dropdown, settings){ dropdown.setValue(this.attr(settings.valueAttr)); }
	
		// attach window behaviors
		$(document)
			// Bind a click event to hide all visible menus when the document is clicked
			.bind("click", function(e){
				// get the target that was clicked
				var $target = $(e.target);
				// check to make sure the clicked element was inside the list
				if( $target.parents().filter(function (){ return this === $list[0]; }).length ){
					// check to see if the user can click on parent items
					if( !settings.allowParentSelect && $target.is(".mc_parent") ) return false;
					
					if( settings.click != null && settings.click.apply($target, [e, thismenu, settings]) == false ){
						return false;
					}
				}

				// close the menu
				thismenu.closeMenu();
			});
			
		// store a reference to the list, if it's not already a jQuery object make it one
		$list = (((typeof list == "object") && !!list.jquery)) ? list : $(list);
		
		// we need to calculate the visual width for each nested list
		$list
			// move the list way off screen
			.css({position: "absolute", top: -10000, left: -10000})
			// find all the ul tags
			.find("ul")
			// add the root ul tag to the array
			.andSelf()
			// make all the nodes visible
			.css("display", "block")
			// loop through each node
			.each(function (){
				var $el = $(this);
				// calculate the width of the element -- using clientWidth is 2x as fast as width()
				$el.data("width", $el[0].clientWidth);
			})
			// now that we've gotten the widths, hide all the lists and move them to x:0, y:0
			.css({top: 0, left: 0, display: "none"});
			
		// mark the root children items
		$list.find("> li").addClass("mc_root");
		// add parent class
		$("li > ul", $list).parent().addClass("mc_parent");

		// create the div to wrap everything in
		$divInput = $('<div class="mcdropdown"><a href="#"></a><input type="hidden" name="' + (el.name || el.id) + '" id="' + (el.id || el.name) + '" /></div>')
			.appendTo($('<div style="position: relative;"></div>'))
			.parent();
			
		// get a reference to the input element and remove it from the DOM				
		var $input = $self.replaceWith($divInput).attr({id: "", name: ""});
		// get a reference to the hidden form field
		var $hidden = $divInput.find(":hidden");
		
		// put the input element back in the div.mcdropdown layer
		$divInput = $divInput.find(".mcdropdown").prepend($input);
		
		// store a reference to this link select
		$.data($hidden[0], "mcDropdown", this);

		// update the height of the outer relative div, this allows us to
		// correctly anchor the dropdown
		$divInput.parent().height($divInput.outerHeight());
		
		// adjust the width of the new input element
		$self
			.width($self.width() - $("a", $divInput).width())
			// make sure we only attach the next events if we're in input element
			.filter(":input")
			// turn autocomplete off
			.attr("autocomplete", "off")
			// add key stroke bindings (IE6 requires keydown)
			.bind("keypress", checkKeypress)
			// prevent user from selecting text
			.bind("mousedown", function (e){ $(this).triggerHandler("focus"); e.stopPropagation(); return false; })
			// disable context menu
			.bind("contextmenu", function (){ return false; })
			// select the text when the cursor is placed in the field
			.bind("focus", onFocus)
			// when the user leaves the text field
			.bind("blur", onBlur);
			
		// IE6 doesn't register certain keypress events, so we must catch them during the keydown event
		if( $.browser.msie ) $self.bind("keydown", function (e){
			// check to see if a key was pressed that IE6 doesn't trigger a keypress event for
			if( ",8,9,37,38,39,40,".indexOf("," + e.keyCode + ",") > -1 ) return checkKeypress(e);
		});
		
		// attach a click event to the anchor
		$("a", $divInput).bind("click", function (e){
			thismenu.openMenu(e);
			return false;
		});
		
		// set the value of the field
		this.setValue = function (value, skipCallback){
			// update the hidden value
			$hidden.val(value);
			// get the display name
			var name = displayString(value);
			
			// run the select callback (some keyboard entry methods will manage this callback manually)
			if( settings.select != null && skipCallback != true ) settings.select.apply(thismenu, [value, name]);
			
			// update the display value and return the jQuery object
			return $self[bInput ? "val" : "text"](name);
		};
		
		// set the default value (but don't run callback)
		if( bInput ) this.setValue($self.attr("defaultValue"), true);
	
		// get the value of the field (returns array)
		this.getValue = function (value){
			return [$hidden.val(), $self[bInput ? "val" : "text"]()];
		};
		
		// open the menu programmatically
		this.openMenu = function (e){
			// if the menu is open, kill processing
			if( $list.is(":visible") ){
				// on a mouse click, close the menu, otherwise just cancel
				return (!!e) ? thismenu.closeMenu() : false;
			}
			
			function open(){
				// columnize the root list
				columnizeList($list).hide();
				// add the bindings to the menu
				addBindings($list);
				
				// anchor the menu relative parent
				anchorTo($divInput.parent(), $list);
				
				// remove existing hover classes, which might exist from keyboard entry
				$list.find(".mc_hover").removeClass("mc_hover");

				// show the menu
				$list[settings.openFx](settings.openSpeed, function (){
					// scroll the list into view
					scrollToView($list);
				});

				// if the bgIframe exists, use the plug-in
				if( isIE6 && !!$.fn.bgIframe ) $list.bgIframe();
			}
			
			// if this is triggered via an event, just open the menu
			if( e ) open();
			// otherwise we need to open the menu asynchronously to avoid collision with $(document).click event
			else setTimeout(open, 1);
		};
		
		// close the menu programmatically
		this.closeMenu = function (e){
			// hide any open menus
			$list.find("ul:visible").parent().each(function (){
				hideBranch.apply(this);
			});
			
			// remove the bindings
			removeBindings($list);
	
			// close the menu
			$list[settings.closeFx](settings.closeSpeed);
		};
	
		function getNodeText($el){
			// return either an empty string or the node's value
			return $el.contents()[0] ? $.trim($el.contents()[0].nodeValue) : "";
		};
		
		function getTreePath($li){
			if( $li.length == 0 ) return [];
	
			var name = [getNodeText($li)];
			// loop through the parents and get the value
			$li.parents().each(function (){
				var $el = $(this);
				// break when we get to the main list element
				if( this === $list[0] ) return false;
				else if( $el.is("li") ) name.push(getNodeText($el));
			});
	
			// return the display name
			return name.reverse();
		};
		
		function displayValue(value){
			// return the path as an array
			return getTreePath(getListItem(value));
		};
		
		function displayString(value){
			// return the display name
			return displayValue(value).join(settings.delim);
		};
		
		function parseTree($selector){
			var s = [], level = (arguments.length > 1) ? ++arguments[1] : 1;
	
			// loop through all the children and store information about the tree
			$("> li", $selector).each(
				function (){
					// get a reference to the current object
					var $self = $(this);
	
					// look for a ul tag as a direct child
					var $ul = $("> ul", this);
					
					// push a reference to the element to the tree array
					s.push({
						// get the name of the node
						  name:     getNodeText($self)
						// store a reference to the current element
						, element:  this
						// parse and store any children items
						, children: ($ul.length) ? parseTree($ul, level) : []
					});
	
				}
			);
			
			return s;
		};
		
		function addBindings(el){
			removeBindings(el);
			$("> li", el)
				.bind("mouseover", hoverOver)
				.bind("mouseout", hoverOut);
		};
		
		function removeBindings(el){
			$("> li", el)
				.unbind("mouseover", hoverOver)
				.unbind("mouseout", hoverOut);
		};
		
		// scroll the current element into view
		function scrollToView($el){
			// get the current position
			var p = position($el);
			// get the screen dimensions
			var sd = getScreenDimensions();
			
			// if we're hidden off the bottom of the page, move up
			if( p.bottom > sd.y ){
				$("html,body").animate({"scrollTop": "+=" + ((p.bottom - sd.y) + settings.screenPadding) + "px" })
			}
		};
		
		function hoverOver(e){
			var self = this;
			var timer = $.data(self, "timer");
			
			// if the timer exists, clear it
			if( !isNaN(timer) ) clearTimeout(timer);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -