📄 zptabs-core.js
字号:
// $Id: zptabs-core.js 7561 2007-07-16 21:06:11Z vkulov $/** * @fileoverview Tabs widget. Extends base Widget class (utils/zpwidget.js). * * <pre> * Copyright (c) 2004-2006 by Zapatec, Inc. * http://www.zapatec.com * 1700 MLK Way, Berkeley, California, * 94709, U.S.A. * All rights reserved. * </pre> *//** * Zapatec.Tab constructor. Creates a new tab object with given * parameters. * * @constructor * @extends Zapatec.Widget * @param {object} objArgs Tab configuration * @private Don't use this class directly * * Constructor recognizes the following properties of the config object * \code * property name | description *------------------------------------------------------------------------------------------------- * id | [string] Id of the tab. Used to identify the tab uniquely. * index | [number] Index where tab is to be inserted at * linkInnerHTML | [string] The HTML content to be placed inside link part * | of the tab. That is the one inside the tab bar that you click on * | to activate the tab (also called tab label). * accessKey | [string] Keyboard shortcut that activates the tab when pressed in * | combination with ALT * content | [mixed, optional] Reference to HTMLElement object holding * | content of the tab or an URL string to tab content * contentType | [string, optional] Meaning of content config option. Valid * | values are "html", "html/text", "html/url". See Zapatec.Pane for * | more details. * url | [string, optional] Url location to fetch tab content from. Deprecated. * | Use content config param along with contentType="html/url" * title | [string, optional] Title html attribute to apply to tab label anchor. * | Acts as a tooltip of the tab label. * tabType | [string] "div" or "iframe" depending on what kind of pane is * | needed for the tab * tab2tab | [boolean] If true, pressing Tab key will open next tab. If false, * | Tab key will also navigate through anchors and form fields inside * | tab. Default: false. * tabParent | [object] Reference to HTMLElement that this tab is to be added to. * | Used internally to decouple Tab from Tabs. * changeUrl | [boolean] Specifies if browser location hash is to be changed * | on every tab change to reflect the current tab * overflow | [string] Tab content overflow html attribute. Default: null (use CSS * | applied overflow style) * refreshOnTabChange | [boolean] When this option is set to true this tab url * | is re-fetched before it becomes active. Default is false. * shouldLoadOnInit | [boolean] When this option is set to true this tab url * | will be loaded as soon as tab is created. Default is false. * activeTabId | [string] Specifies the tab that is to become active after Tabs * | initialization. If not specified the first tab will become active. * \endcode * */Zapatec.Tab = function(objArgs) { if (arguments.length == 0) { objArgs = {}; } // Call constructor of superclass Zapatec.Tab.SUPERconstructor.call(this, objArgs);};/** * Unique static id of the widget class. Gives ability for Zapatec#inherit to * determine and store path to this file correctly when it is included using * Zapatec#include. When this file is included using Zapatec#include or path * to this file is gotten using Zapatec#getPath, this value must be specified * as script id. * @private */Zapatec.Tab.id = 'Zapatec.Tab';// Inherit WidgetZapatec.inherit(Zapatec.Tab, Zapatec.Widget);/** * Initializes object. * * @param {object} objArgs User configuration */Zapatec.Tab.prototype.init = function(objArgs) { // processing Widget functionality Zapatec.Tab.SUPERclass.init.call(this, objArgs); this.createTab();};/** * Creates elements needed for the new tab */Zapatec.Tab.prototype.createTab = function () { // Reference to tab link element this.createProperty(this, 'linkNode', null); // Reference to pane containing tab content this.createProperty(this, 'container', null); // Child element which gets focus first (needed for keyboard navigation) this.createProperty(this, 'focusOn', null); this.createProperty(this, 'linkHash', null); // If set an onTabChange event is to be called after onContentLoad this.createProperty(this, 'pendingOnTabChange', null); // Create content with pane this.container = new Zapatec.Pane({ containerType : this.config.tabType, parent : this.config.tabParent, overflow : this.config.overflow, id: this.config.id }); this.container.removeBorder(); // Add "zpTab" class to to all tab content divs var className = "zpTab"; // If a class name is specified for the tab content div if (this.config.className) { className += " " + this.config.className; } // Set tab container className this.container.getContainer().className = className; var self = this; // Define pane content loaded handler var onContentLoaded = function() { if (self.pendingOnTabChange) { self.pendingOnTabChange(self); self.pendingOnTabChange = null; } self.fireEvent('tabOnLoad'); setTimeout(function() { // Re-add pane contentLoaded listener self.container.addEventListener('contentLoaded', self.onContentLoaded); }, 10); } // Store onLoad event handler this.createProperty(this, 'onContentLoaded', onContentLoaded); // Add pane contentLoaded listener this.container.addEventListener('contentLoaded', onContentLoaded); // Hide content this.container.hide(); this.container.getContainer().style.width = '100%'; this.container.getContainer().style.height = '100%'; if (!this.config.url) { // Update tab content this.setPaneContent(); } else { if (this.config.shouldLoadOnInit) { // Update tab content this.setPaneContent(); } } // Get id if (this.config.id) { this.id = this.config.id; } else { this.id = this.container.getContainer().getAttribute('id'); if (typeof this.id == 'string') { this.container.getContainer().removeAttribute('id'); } } if (typeof this.id != 'string' || !this.id.length) { // Generate unique id this.id = Zapatec.Utils.generateID('tab'); } // Create link node this.linkNode = Zapatec.Utils.createElement('div'); this.linkNode.onmouseover = function() { var outer = Zapatec.Utils.getFirstChild(self.linkNode, "div"); Zapatec.Utils.addClass(outer, "zpTabsHover"); } this.linkNode.onmouseout = function() { var outer = Zapatec.Utils.getFirstChild(self.linkNode, "div"); Zapatec.Utils.removeClass(outer, "zpTabsHover"); } this.linkNode.className = "zpTab"; this.linkNode.name = this.id; // Need "<div><div>" for themes var innerClass = "zpTabLinkInner"; if (this.config.closable) { innerClass += " zpTabClosable"; } var innerHtml = '<div class="zpTabLinkOuter"><div class="' + innerClass + '">' + '<div class="zpTabAnchorHolder"><a '; if (this.config.accessKey) { innerHtml += 'accessKey="' + this.config.accessKey + '" '; } if (this.config.title) { innerHtml += 'title="' + this.config.title + '" '; } innerHtml += '>' + this.config.linkInnerHTML + '</a></div>'; if (this.config.closable) { var closeUrl = this.config.themePath + this.config.theme + "/close.gif"; var closeImgHtml = '<img class="zpTabClose" border=0 src="' + closeUrl + '">'; innerHtml += closeImgHtml; } innerHtml += '<div class="zpTabsClearer"></div>'; innerHtml += '</div></div>'; this.linkNode.innerHTML = innerHtml; var self = this; var closeImages = this.linkNode.getElementsByTagName('img'); if (closeImages && 0 < closeImages.length) { closeImages[0].onmousedown = function(ev) { Zapatec.Tab.CloseTab(self.config.tabsId, self.id); Zapatec.Utils.stopEvent(ev); return false; } } // Mouse navigation support this.onActivate = function(e) { self.fireEvent('activateTab'); if (self.blur) { self.blur(); } // Don't navigate to link (don't refresh the page) var doNavigate = false; // If url is to be changed if (self.config.changeUrl) { if (Zapatec.is_khtml) { // Make safari navigate the link. // Changing location.hash does not work properly on Safari doNavigate = true; } else { // Modify window URL window.location.hash = self.linkHash; } } Zapatec.Utils.stopEvent(e); return doNavigate; }; // If tab are to be changed on mouse over if (this.config.mouseOverChangesTab) { this.linkNode.onmouseover = this.onActivate; } else { this.linkNode.onclick = this.onActivate; } // Keyboard navigation support this.linkNode.tabIndex = Zapatec.Tab.tabIndex; if (!this.tab2tab) { // Next tabIndex is reserved for tab content Zapatec.Tab.tabIndex += 2; } // Activate tab on focus this.linkNode.onfocus = this.onActivate; // Setup keys this.linkNode.onkeydown = function(ev) { ev || (ev = window.event); switch (ev.keyCode) { case 13: // Enter case 32: // Space if (self.focusOn && self.focusOn.focus) { self.focusOn.focus(); } // Stop event return false; } // Continue event return true; } // Determine child element which gets focus first if (this.container.getContainer().hasChildNodes()) { this.getFocusOn(); }}/** * Sets tab link href given the hash * * @private * @param {string} linkHash Bookmark hash to set to link href */Zapatec.Tab.prototype.setLinkHash = function(linkHash) { this.linkHash = linkHash; this.linkNode.setAttribute('href', '#' + linkHash);}/** * Configures the widget. Gets called from init and reconfigure methods of * superclass. * * @private * @param {object} objArgs User configuration */Zapatec.Tab.prototype.configure = function(objArgs) { // Define config options // Id of the tab this.defineConfigOption('id', null); // Index of the tab this.defineConfigOption('index', -1); // Tab link inner html this.defineConfigOption('linkInnerHTML', ''); // Tab access key this.defineConfigOption('accessKey', ''); // Tab content this.defineConfigOption('content', null); // Tab content type this.defineConfigOption('contentType', null); // URL of the content this.defineConfigOption('url', ''); //should we show content in IFRAME Pane or just simple div Pane this.defineConfigOption('tabType', "div"); // Keyboard navigation type this.defineConfigOption('tab2tab', false); // Tab parent this.defineConfigOption('tabParent', null); this.defineConfigOption('title', null); // Specifies if tab can be closed using an x button that is visible this.defineConfigOption('closable', false); // Specifies what happens then the x button is clicked this.defineConfigOption('closeAction', 'close'); // If browser url needs to be changed on every tab change this.defineConfigOption('changeUrl', true); // Determine tab content overflow style attribute this.defineConfigOption('overflow', null); // Determine if tabs are to be changed on mouse over this.defineConfigOption('mouseOverChangesTab', false); // Determine if tabs are to be re-fetched every time they are activated this.defineConfigOption('refreshOnTabChange', false); // Determine if tab content is to be fetched on tab creation this.defineConfigOption('shouldLoadOnInit', false); this.defineConfigOption('tabsId', null); // Determines tab initial visibility this.defineConfigOption('visible', true); // Determines tab content container class names this.defineConfigOption('className', null); this.defineConfigOption('langId', Zapatec.Tabs.id); this.defineConfigOption('lang', "eng"); // Call parent method Zapatec.Tab.SUPERclass.configure.call(this, objArgs); // Check if required param "tabParent" is defined if (typeof(this.config.tabParent) == "undefined") { this.initLang(); Zapatec.Log({description: this.getMessage("unknownTabParentError")}) return false; } // Check keyboard navigation type if (this.config.tab2tab && false != this.config.tab2tab) { this.config.tab2tab = true; } // Check tabType if (typeof this.config.tabType == "string") { this.config.tabType = this.config.tabType.toLowerCase(); } if (this.config.tabType != "div" && this.config.tabType != "iframe") { this.config.tabType = "div"; } if (this.config.index < 0) { this.config.index = -1; }};/** * Counter that gets increased after Tab is added. Required for keyboard * navigation support. * * Note: * In Opera tabIndex property value must be > 0, otherwise node is ignored. * Mozilla starts travelling from nodes with tabIndex > 0. * IE starts travelling from nodes with tabIndex == 0. * All nodes without tabIndex set explicitly have tabIndex == 0. */Zapatec.Tab.tabIndex = 1000;/** * Determines child node of the container which gets focus first. * Needed for keyboard navigation. * @private */Zapatec.Tab.prototype.getFocusOn = function() { // Remove old value this.focusOn = null; // Check keyboard navigation type if (this.tab2tab) { return; } // Put it in separate process to speed up initialization var self = this; setTimeout(function() { // Flag to determine lower tabIndex var iTabIndex = 0; // Gets element with lower tabIndex function parse(objNode) { var objChild = objNode.firstChild; while (objChild) { if (objChild.nodeType == 1) { // ELEMENT_NODE var strTag = objChild.tagName.toLowerCase(); if (strTag == 'a' || strTag == 'input' || strTag == 'select' || strTag == 'textarea' || strTag == 'button') { // Element may obtain focus if (!self.focusOn) { self.focusOn = objChild; } else if (objChild.tabIndex && objChild.tabIndex > 0 && (!iTabIndex || iTabIndex > objChild.tabIndex)) { self.focusOn = objChild; iTabIndex = objChild.tabIndex; } if (!objChild.tabIndex) { objChild.tabIndex = self.linkNode.tabIndex + 1; } } parse(objChild); } objChild = objChild.nextSibling; } } ; // Parse tab contenet parse(self.container); }, 0);};/** * Sets tab content from given HTML fragment. * * @param {string} strHtml HTML fragment. * @private */Zapatec.Tab.prototype.setInnerHtml = function(strHtml) { // Set tab content Zapatec.Transport.setInnerHtml({ html: strHtml, container: this.container.getContainer() }); // Determine child element which gets focus first this.getFocusOn();}/** * Sets tab pane content * * @public * @param {mixed} content value for the content * @param {string} type type of content: "html", "html/text", "html/url" * @return {boolean} true if successfull, otherwise false.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -