diff options
author | Aurélien Bompard <aurelien@bompard.org> | 2013-01-25 15:49:53 +0100 |
---|---|---|
committer | Aurélien Bompard <aurelien@bompard.org> | 2013-01-25 15:49:53 +0100 |
commit | d4ecad9325292f865e58b9fe7f58927f6e5af953 (patch) | |
tree | 8537b3ea831beb89fbb2238c64f0c280b07bcfe6 /hyperkitty/static/js | |
parent | 9e179cd7889ab9f47c41cee8ae9025ddf81aea04 (diff) | |
download | hyperkitty-d4ecad9325292f865e58b9fe7f58927f6e5af953.tar.gz hyperkitty-d4ecad9325292f865e58b9fe7f58927f6e5af953.tar.xz hyperkitty-d4ecad9325292f865e58b9fe7f58927f6e5af953.zip |
Style changes
- move imported JS/CSS libs to a separate directory
- real accordion for the months list
- the top navbar is not black anymore
Diffstat (limited to 'hyperkitty/static/js')
-rw-r--r-- | hyperkitty/static/js/hyperkitty.js | 2 | ||||
-rw-r--r-- | hyperkitty/static/js/libs/bootstrap.js | 2159 | ||||
-rw-r--r-- | hyperkitty/static/js/libs/bootstrap.min.js | 6 | ||||
-rw-r--r-- | hyperkitty/static/js/libs/jquery-1.8.3.min.js | 2 | ||||
-rw-r--r-- | hyperkitty/static/js/libs/jquery-ui-1.9.1.custom.min.js | 6 | ||||
-rw-r--r-- | hyperkitty/static/js/libs/jquery-ui-selection.txt | 1 | ||||
-rw-r--r-- | hyperkitty/static/js/libs/jquery.expander.js | 382 | ||||
-rw-r--r-- | hyperkitty/static/js/libs/protovis-d3.1.js | 7725 |
8 files changed, 1 insertions, 10282 deletions
diff --git a/hyperkitty/static/js/hyperkitty.js b/hyperkitty/static/js/hyperkitty.js index bc04e42..ee61a82 100644 --- a/hyperkitty/static/js/hyperkitty.js +++ b/hyperkitty/static/js/hyperkitty.js @@ -172,5 +172,5 @@ $(document).ready(function() { setup_attachments(); setup_add_tag(); setup_quotes(); - $("#archives").accordion({navigation: true}); + $("#months-list").accordion({navigation: true}); }); diff --git a/hyperkitty/static/js/libs/bootstrap.js b/hyperkitty/static/js/libs/bootstrap.js deleted file mode 100644 index 6c15a58..0000000 --- a/hyperkitty/static/js/libs/bootstrap.js +++ /dev/null @@ -1,2159 +0,0 @@ -/* =================================================== - * bootstrap-transition.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#transitions - * =================================================== - * Copyright 2012 Twitter, Inc. - * - * 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. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) - * ======================================================= */ - - $(function () { - - $.support.transition = (function () { - - var transitionEnd = (function () { - - var el = document.createElement('bootstrap') - , transEndEventNames = { - 'WebkitTransition' : 'webkitTransitionEnd' - , 'MozTransition' : 'transitionend' - , 'OTransition' : 'oTransitionEnd otransitionend' - , 'transition' : 'transitionend' - } - , name - - for (name in transEndEventNames){ - if (el.style[name] !== undefined) { - return transEndEventNames[name] - } - } - - }()) - - return transitionEnd && { - end: transitionEnd - } - - })() - - }) - -}(window.jQuery);/* ========================================================== - * bootstrap-alert.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#alerts - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * 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. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* ALERT CLASS DEFINITION - * ====================== */ - - var dismiss = '[data-dismiss="alert"]' - , Alert = function (el) { - $(el).on('click', dismiss, this.close) - } - - Alert.prototype.close = function (e) { - var $this = $(this) - , selector = $this.attr('data-target') - , $parent - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - $parent = $(selector) - - e && e.preventDefault() - - $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) - - $parent.trigger(e = $.Event('close')) - - if (e.isDefaultPrevented()) return - - $parent.removeClass('in') - - function removeElement() { - $parent - .trigger('closed') - .remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent.on($.support.transition.end, removeElement) : - removeElement() - } - - - /* ALERT PLUGIN DEFINITION - * ======================= */ - - var old = $.fn.alert - - $.fn.alert = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('alert') - if (!data) $this.data('alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - $.fn.alert.Constructor = Alert - - - /* ALERT NO CONFLICT - * ================= */ - - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this - } - - - /* ALERT DATA-API - * ============== */ - - $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) - -}(window.jQuery);/* ============================================================ - * bootstrap-button.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#buttons - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * 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. - * ============================================================ */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* BUTTON PUBLIC CLASS DEFINITION - * ============================== */ - - var Button = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, $.fn.button.defaults, options) - } - - Button.prototype.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) - } - - Button.prototype.toggle = function () { - var $parent = this.$element.closest('[data-toggle="buttons-radio"]') - - $parent && $parent - .find('.active') - .removeClass('active') - - this.$element.toggleClass('active') - } - - - /* BUTTON PLUGIN DEFINITION - * ======================== */ - - var old = $.fn.button - - $.fn.button = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('button') - , options = typeof option == 'object' && option - if (!data) $this.data('button', (data = new Button(this, options))) - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) - }) - } - - $.fn.button.defaults = { - loadingText: 'loading...' - } - - $.fn.button.Constructor = Button - - - /* BUTTON NO CONFLICT - * ================== */ - - $.fn.button.noConflict = function () { - $.fn.button = old - return this - } - - - /* BUTTON DATA-API - * =============== */ - - $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - $btn.button('toggle') - }) - -}(window.jQuery);/* ========================================================== - * bootstrap-carousel.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#carousel - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * 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. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* CAROUSEL CLASS DEFINITION - * ========================= */ - - var Carousel = function (element, options) { - this.$element = $(element) - this.options = options - this.options.pause == 'hover' && this.$element - .on('mouseenter', $.proxy(this.pause, this)) - .on('mouseleave', $.proxy(this.cycle, this)) - } - - Carousel.prototype = { - - cycle: function (e) { - if (!e) this.paused = false - this.options.interval - && !this.paused - && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) - return this - } - - , to: function (pos) { - var $active = this.$element.find('.item.active') - , children = $active.parent().children() - , activePos = children.index($active) - , that = this - - if (pos > (children.length - 1) || pos < 0) return - - if (this.sliding) { - return this.$element.one('slid', function () { - that.to(pos) - }) - } - - if (activePos == pos) { - return this.pause().cycle() - } - - return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) - } - - , pause: function (e) { - if (!e) this.paused = true - if (this.$element.find('.next, .prev').length && $.support.transition.end) { - this.$element.trigger($.support.transition.end) - this.cycle() - } - clearInterval(this.interval) - this.interval = null - return this - } - - , next: function () { - if (this.sliding) return - return this.slide('next') - } - - , prev: function () { - if (this.sliding) return - return this.slide('prev') - } - - , slide: function (type, next) { - var $active = this.$element.find('.item.active') - , $next = next || $active[type]() - , isCycling = this.interval - , direction = type == 'next' ? 'left' : 'right' - , fallback = type == 'next' ? 'first' : 'last' - , that = this - , e - - this.sliding = true - - isCycling && this.pause() - - $next = $next.length ? $next : this.$element.find('.item')[fallback]() - - e = $.Event('slide', { - relatedTarget: $next[0] - }) - - if ($next.hasClass('active')) return - - if ($.support.transition && this.$element.hasClass('slide')) { - this.$element.trigger(e) - if (e.isDefaultPrevented()) return - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - this.$element.one($.support.transition.end, function () { - $next.removeClass([type, direction].join(' ')).addClass('active') - $active.removeClass(['active', direction].join(' ')) - that.sliding = false - setTimeout(function () { that.$element.trigger('slid') }, 0) - }) - } else { - this.$element.trigger(e) - if (e.isDefaultPrevented()) return - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger('slid') - } - - isCycling && this.cycle() - - return this - } - - } - - - /* CAROUSEL PLUGIN DEFINITION - * ========================== */ - - var old = $.fn.carousel - - $.fn.carousel = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('carousel') - , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) - , action = typeof option == 'string' ? option : options.slide - if (!data) $this.data('carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (action) data[action]() - else if (options.interval) data.cycle() - }) - } - - $.fn.carousel.defaults = { - interval: 5000 - , pause: 'hover' - } - - $.fn.carousel.Constructor = Carousel - - - /* CAROUSEL NO CONFLICT - * ==================== */ - - $.fn.carousel.noConflict = function () { - $.fn.carousel = old - return this - } - - /* CAROUSEL DATA-API - * ================= */ - - $(document).on('click.carousel.data-api', '[data-slide]', function (e) { - var $this = $(this), href - , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 - , options = $.extend({}, $target.data(), $this.data()) - $target.carousel(options) - e.preventDefault() - }) - -}(window.jQuery);/* ============================================================= - * bootstrap-collapse.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#collapse - * ============================================================= - * Copyright 2012 Twitter, Inc. - * - * 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. - * ============================================================ */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* COLLAPSE PUBLIC CLASS DEFINITION - * ================================ */ - - var Collapse = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, $.fn.collapse.defaults, options) - - if (this.options.parent) { - this.$parent = $(this.options.parent) - } - - this.options.toggle && this.toggle() - } - - Collapse.prototype = { - - constructor: Collapse - - , dimension: function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } - - , show: function () { - var dimension - , scroll - , actives - , hasData - - if (this.transitioning) return - - dimension = this.dimension() - scroll = $.camelCase(['scroll', dimension].join('-')) - actives = this.$parent && this.$parent.find('> .accordion-group > .in') - - if (actives && actives.length) { - hasData = actives.data('collapse') - if (hasData && hasData.transitioning) return - actives.collapse('hide') - hasData || actives.data('collapse', null) - } - - this.$element[dimension](0) - this.transition('addClass', $.Event('show'), 'shown') - $.support.transition && this.$element[dimension](this.$element[0][scroll]) - } - - , hide: function () { - var dimension - if (this.transitioning) return - dimension = this.dimension() - this.reset(this.$element[dimension]()) - this.transition('removeClass', $.Event('hide'), 'hidden') - this.$element[dimension](0) - } - - , reset: function (size) { - var dimension = this.dimension() - - this.$element - .removeClass('collapse') - [dimension](size || 'auto') - [0].offsetWidth - - this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') - - return this - } - - , transition: function (method, startEvent, completeEvent) { - var that = this - , complete = function () { - if (startEvent.type == 'show') that.reset() - that.transitioning = 0 - that.$element.trigger(completeEvent) - } - - this.$element.trigger(startEvent) - - if (startEvent.isDefaultPrevented()) return - - this.transitioning = 1 - - this.$element[method]('in') - - $.support.transition && this.$element.hasClass('collapse') ? - this.$element.one($.support.transition.end, complete) : - complete() - } - - , toggle: function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() - } - - } - - - /* COLLAPSE PLUGIN DEFINITION - * ========================== */ - - var old = $.fn.collapse - - $.fn.collapse = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('collapse') - , options = typeof option == 'object' && option - if (!data) $this.data('collapse', (data = new Collapse(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.collapse.defaults = { - toggle: true - } - - $.fn.collapse.Constructor = Collapse - - - /* COLLAPSE NO CONFLICT - * ==================== */ - - $.fn.collapse.noConflict = function () { - $.fn.collapse = old - return this - } - - - /* COLLAPSE DATA-API - * ================= */ - - $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { - var $this = $(this), href - , target = $this.attr('data-target') - || e.preventDefault() - || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 - , option = $(target).data('collapse') ? 'toggle' : $this.data() - $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') - $(target).collapse(option) - }) - -}(window.jQuery);/* ============================================================ - * bootstrap-dropdown.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#dropdowns - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * 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. - * ============================================================ */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* DROPDOWN CLASS DEFINITION - * ========================= */ - - var toggle = '[data-toggle=dropdown]' - , Dropdown = function (element) { - var $el = $(element).on('click.dropdown.data-api', this.toggle) - $('html').on('click.dropdown.data-api', function () { - $el.parent().removeClass('open') - }) - } - - Dropdown.prototype = { - - constructor: Dropdown - - , toggle: function (e) { - var $this = $(this) - , $parent - , isActive - - if ($this.is('.disabled, :disabled')) return - - $parent = getParent($this) - - isActive = $parent.hasClass('open') - - clearMenus() - - if (!isActive) { - $parent.toggleClass('open') - } - - $this.focus() - - return false - } - - , keydown: function (e) { - var $this - , $items - , $active - , $parent - , isActive - , index - - if (!/(38|40|27)/.test(e.keyCode)) return - - $this = $(this) - - e.preventDefault() - e.stopPropagation() - - if ($this.is('.disabled, :disabled')) return - - $parent = getParent($this) - - isActive = $parent.hasClass('open') - - if (!isActive || (isActive && e.keyCode == 27)) return $this.click() - - $items = $('[role=menu] li:not(.divider):visible a', $parent) - - if (!$items.length) return - - index = $items.index($items.filter(':focus')) - - if (e.keyCode == 38 && index > 0) index-- // up - if (e.keyCode == 40 && index < $items.length - 1) index++ // down - if (!~index) index = 0 - - $items - .eq(index) - .focus() - } - - } - - function clearMenus() { - $(toggle).each(function () { - getParent($(this)).removeClass('open') - }) - } - - function getParent($this) { - var selector = $this.attr('data-target') - , $parent - - if (!selector) { - selector = $this.attr('href') - selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - $parent = $(selector) - $parent.length || ($parent = $this.parent()) - - return $parent - } - - - /* DROPDOWN PLUGIN DEFINITION - * ========================== */ - - var old = $.fn.dropdown - - $.fn.dropdown = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('dropdown') - if (!data) $this.data('dropdown', (data = new Dropdown(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - $.fn.dropdown.Constructor = Dropdown - - - /* DROPDOWN NO CONFLICT - * ==================== */ - - $.fn.dropdown.noConflict = function () { - $.fn.dropdown = old - return this - } - - - /* APPLY TO STANDARD DROPDOWN ELEMENTS - * =================================== */ - - $(document) - .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus) - .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) - .on('touchstart.dropdown.data-api', '.dropdown-menu', function (e) { e.stopPropagation() }) - .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle) - .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) - -}(window.jQuery);/* ========================================================= - * bootstrap-modal.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#modals - * ========================================================= - * Copyright 2012 Twitter, Inc. - * - * 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. - * ========================================================= */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* MODAL CLASS DEFINITION - * ====================== */ - - var Modal = function (element, options) { - this.options = options - this.$element = $(element) - .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) - this.options.remote && this.$element.find('.modal-body').load(this.options.remote) - } - - Modal.prototype = { - - constructor: Modal - - , toggle: function () { - return this[!this.isShown ? 'show' : 'hide']() - } - - , show: function () { - var that = this - , e = $.Event('show') - - this.$element.trigger(e) - - if (this.isShown || e.isDefaultPrevented()) return - - this.isShown = true - - this.escape() - - this.backdrop(function () { - var transition = $.support.transition && that.$element.hasClass('fade') - - if (!that.$element.parent().length) { - that.$element.appendTo(document.body) //don't move modals dom position - } - - that.$element - .show() - - if (transition) { - that.$element[0].offsetWidth // force reflow - } - - that.$element - .addClass('in') - .attr('aria-hidden', false) - - that.enforceFocus() - - transition ? - that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) : - that.$element.focus().trigger('shown') - - }) - } - - , hide: function (e) { - e && e.preventDefault() - - var that = this - - e = $.Event('hide') - - this.$element.trigger(e) - - if (!this.isShown || e.isDefaultPrevented()) return - - this.isShown = false - - this.escape() - - $(document).off('focusin.modal') - - this.$element - .removeClass('in') - .attr('aria-hidden', true) - - $.support.transition && this.$element.hasClass('fade') ? - this.hideWithTransition() : - this.hideModal() - } - - , enforceFocus: function () { - var that = this - $(document).on('focusin.modal', function (e) { - if (that.$element[0] !== e.target && !that.$element.has(e.target).length) { - that.$element.focus() - } - }) - } - - , escape: function () { - var that = this - if (this.isShown && this.options.keyboard) { - this.$element.on('keyup.dismiss.modal', function ( e ) { - e.which == 27 && that.hide() - }) - } else if (!this.isShown) { - this.$element.off('keyup.dismiss.modal') - } - } - - , hideWithTransition: function () { - var that = this - , timeout = setTimeout(function () { - that.$element.off($.support.transition.end) - that.hideModal() - }, 500) - - this.$element.one($.support.transition.end, function () { - clearTimeout(timeout) - that.hideModal() - }) - } - - , hideModal: function (that) { - this.$element - .hide() - .trigger('hidden') - - this.backdrop() - } - - , removeBackdrop: function () { - this.$backdrop.remove() - this.$backdrop = null - } - - , backdrop: function (callback) { - var that = this - , animate = this.$element.hasClass('fade') ? 'fade' : '' - - if (this.isShown && this.options.backdrop) { - var doAnimate = $.support.transition && animate - - this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />') - .appendTo(document.body) - - this.$backdrop.click( - this.options.backdrop == 'static' ? - $.proxy(this.$element[0].focus, this.$element[0]) - : $.proxy(this.hide, this) - ) - - if (doAnimate) this.$backdrop[0].offsetWidth // force reflow - - this.$backdrop.addClass('in') - - doAnimate ? - this.$backdrop.one($.support.transition.end, callback) : - callback() - - } else if (!this.isShown && this.$backdrop) { - this.$backdrop.removeClass('in') - - $.support.transition && this.$element.hasClass('fade')? - this.$backdrop.one($.support.transition.end, $.proxy(this.removeBackdrop, this)) : - this.removeBackdrop() - - } else if (callback) { - callback() - } - } - } - - - /* MODAL PLUGIN DEFINITION - * ======================= */ - - var old = $.fn.modal - - $.fn.modal = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('modal') - , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option) - if (!data) $this.data('modal', (data = new Modal(this, options))) - if (typeof option == 'string') data[option]() - else if (options.show) data.show() - }) - } - - $.fn.modal.defaults = { - backdrop: true - , keyboard: true - , show: true - } - - $.fn.modal.Constructor = Modal - - - /* MODAL NO CONFLICT - * ================= */ - - $.fn.modal.noConflict = function () { - $.fn.modal = old - return this - } - - - /* MODAL DATA-API - * ============== */ - - $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) { - var $this = $(this) - , href = $this.attr('href') - , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 - , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data()) - - e.preventDefault() - - $target - .modal(option) - .one('hide', function () { - $this.focus() - }) - }) - -}(window.jQuery); -/* =========================================================== - * bootstrap-tooltip.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#tooltips - * Inspired by the original jQuery.tipsy by Jason Frame - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * 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. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TOOLTIP PUBLIC CLASS DEFINITION - * =============================== */ - - var Tooltip = function (element, options) { - this.init('tooltip', element, options) - } - - Tooltip.prototype = { - - constructor: Tooltip - - , init: function (type, element, options) { - var eventIn - , eventOut - - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.enabled = true - - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) - } - - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } - - , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) - - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay - , hide: options.delay - } - } - - return options - } - - , enter: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (!self.options.delay || !self.options.delay.show) return self.show() - - clearTimeout(this.timeout) - self.hoverState = 'in' - this.timeout = setTimeout(function() { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } - - , leave: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (this.timeout) clearTimeout(this.timeout) - if (!self.options.delay || !self.options.delay.hide) return self.hide() - - self.hoverState = 'out' - this.timeout = setTimeout(function() { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } - - , show: function () { - var $tip - , inside - , pos - , actualWidth - , actualHeight - , placement - , tp - - if (this.hasContent() && this.enabled) { - $tip = this.tip() - this.setContent() - - if (this.options.animation) { - $tip.addClass('fade') - } - - placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement - - inside = /in/.test(placement) - - $tip - .detach() - .css({ top: 0, left: 0, display: 'block' }) - .insertAfter(this.$element) - - pos = this.getPosition(inside) - - actualWidth = $tip[0].offsetWidth - actualHeight = $tip[0].offsetHeight - - switch (inside ? placement.split(' ')[1] : placement) { - case 'bottom': - tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'top': - tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'left': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} - break - case 'right': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} - break - } - - $tip - .offset(tp) - .addClass(placement) - .addClass('in') - } - } - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } - - , hide: function () { - var that = this - , $tip = this.tip() - - $tip.removeClass('in') - - function removeWithAnimation() { - var timeout = setTimeout(function () { - $tip.off($.support.transition.end).detach() - }, 500) - - $tip.one($.support.transition.end, function () { - clearTimeout(timeout) - $tip.detach() - }) - } - - $.support.transition && this.$tip.hasClass('fade') ? - removeWithAnimation() : - $tip.detach() - - return this - } - - , fixTitle: function () { - var $e = this.$element - if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') - } - } - - , hasContent: function () { - return this.getTitle() - } - - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) - } - - , getTitle: function () { - var title - , $e = this.$element - , o = this.options - - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - - return title - } - - , tip: function () { - return this.$tip = this.$tip || $(this.options.template) - } - - , validate: function () { - if (!this.$element[0].parentNode) { - this.hide() - this.$element = null - this.options = null - } - } - - , enable: function () { - this.enabled = true - } - - , disable: function () { - this.enabled = false - } - - , toggleEnabled: function () { - this.enabled = !this.enabled - } - - , toggle: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - self[self.tip().hasClass('in') ? 'hide' : 'show']() - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - } - - - /* TOOLTIP PLUGIN DEFINITION - * ========================= */ - - var old = $.fn.tooltip - - $.fn.tooltip = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tooltip') - , options = typeof option == 'object' && option - if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tooltip.Constructor = Tooltip - - $.fn.tooltip.defaults = { - animation: true - , placement: 'top' - , selector: false - , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>' - , trigger: 'hover' - , title: '' - , delay: 0 - , html: false - } - - - /* TOOLTIP NO CONFLICT - * =================== */ - - $.fn.tooltip.noConflict = function () { - $.fn.tooltip = old - return this - } - -}(window.jQuery);/* =========================================================== - * bootstrap-popover.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#popovers - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * 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. - * =========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* POPOVER PUBLIC CLASS DEFINITION - * =============================== */ - - var Popover = function (element, options) { - this.init('popover', element, options) - } - - - /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js - ========================================== */ - - Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, { - - constructor: Popover - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - , content = this.getContent() - - $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) - $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content) - - $tip.removeClass('fade top bottom left right in') - } - - , hasContent: function () { - return this.getTitle() || this.getContent() - } - - , getContent: function () { - var content - , $e = this.$element - , o = this.options - - content = $e.attr('data-content') - || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) - - return content - } - - , tip: function () { - if (!this.$tip) { - this.$tip = $(this.options.template) - } - return this.$tip - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - }) - - - /* POPOVER PLUGIN DEFINITION - * ======================= */ - - var old = $.fn.popover - - $.fn.popover = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('popover') - , options = typeof option == 'object' && option - if (!data) $this.data('popover', (data = new Popover(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.popover.Constructor = Popover - - $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, { - placement: 'right' - , trigger: 'click' - , content: '' - , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"></div></div></div>' - }) - - - /* POPOVER NO CONFLICT - * =================== */ - - $.fn.popover.noConflict = function () { - $.fn.popover = old - return this - } - -}(window.jQuery);/* ============================================================= - * bootstrap-scrollspy.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#scrollspy - * ============================================================= - * Copyright 2012 Twitter, Inc. - * - * 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. - * ============================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* SCROLLSPY CLASS DEFINITION - * ========================== */ - - function ScrollSpy(element, options) { - var process = $.proxy(this.process, this) - , $element = $(element).is('body') ? $(window) : $(element) - , href - this.options = $.extend({}, $.fn.scrollspy.defaults, options) - this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process) - this.selector = (this.options.target - || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 - || '') + ' .nav li > a' - this.$body = $('body') - this.refresh() - this.process() - } - - ScrollSpy.prototype = { - - constructor: ScrollSpy - - , refresh: function () { - var self = this - , $targets - - this.offsets = $([]) - this.targets = $([]) - - $targets = this.$body - .find(this.selector) - .map(function () { - var $el = $(this) - , href = $el.data('target') || $el.attr('href') - , $href = /^#\w/.test(href) && $(href) - return ( $href - && $href.length - && [[ $href.position().top + self.$scrollElement.scrollTop(), href ]] ) || null - }) - .sort(function (a, b) { return a[0] - b[0] }) - .each(function () { - self.offsets.push(this[0]) - self.targets.push(this[1]) - }) - } - - , process: function () { - var scrollTop = this.$scrollElement.scrollTop() + this.options.offset - , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight - , maxScroll = scrollHeight - this.$scrollElement.height() - , offsets = this.offsets - , targets = this.targets - , activeTarget = this.activeTarget - , i - - if (scrollTop >= maxScroll) { - return activeTarget != (i = targets.last()[0]) - && this.activate ( i ) - } - - for (i = offsets.length; i--;) { - activeTarget != targets[i] - && scrollTop >= offsets[i] - && (!offsets[i + 1] || scrollTop <= offsets[i + 1]) - && this.activate( targets[i] ) - } - } - - , activate: function (target) { - var active - , selector - - this.activeTarget = target - - $(this.selector) - .parent('.active') - .removeClass('active') - - selector = this.selector - + '[data-target="' + target + '"],' - + this.selector + '[href="' + target + '"]' - - active = $(selector) - .parent('li') - .addClass('active') - - if (active.parent('.dropdown-menu').length) { - active = active.closest('li.dropdown').addClass('active') - } - - active.trigger('activate') - } - - } - - - /* SCROLLSPY PLUGIN DEFINITION - * =========================== */ - - var old = $.fn.scrollspy - - $.fn.scrollspy = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('scrollspy') - , options = typeof option == 'object' && option - if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.scrollspy.Constructor = ScrollSpy - - $.fn.scrollspy.defaults = { - offset: 10 - } - - - /* SCROLLSPY NO CONFLICT - * ===================== */ - - $.fn.scrollspy.noConflict = function () { - $.fn.scrollspy = old - return this - } - - - /* SCROLLSPY DATA-API - * ================== */ - - $(window).on('load', function () { - $('[data-spy="scroll"]').each(function () { - var $spy = $(this) - $spy.scrollspy($spy.data()) - }) - }) - -}(window.jQuery);/* ======================================================== - * bootstrap-tab.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#tabs - * ======================================================== - * Copyright 2012 Twitter, Inc. - * - * 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. - * ======================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TAB CLASS DEFINITION - * ==================== */ - - var Tab = function (element) { - this.element = $(element) - } - - Tab.prototype = { - - constructor: Tab - - , show: function () { - var $this = this.element - , $ul = $this.closest('ul:not(.dropdown-menu)') - , selector = $this.attr('data-target') - , previous - , $target - , e - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - if ( $this.parent('li').hasClass('active') ) return - - previous = $ul.find('.active:last a')[0] - - e = $.Event('show', { - relatedTarget: previous - }) - - $this.trigger(e) - - if (e.isDefaultPrevented()) return - - $target = $(selector) - - this.activate($this.parent('li'), $ul) - this.activate($target, $target.parent(), function () { - $this.trigger({ - type: 'shown' - , relatedTarget: previous - }) - }) - } - - , activate: function ( element, container, callback) { - var $active = container.find('> .active') - , transition = callback - && $.support.transition - && $active.hasClass('fade') - - function next() { - $active - .removeClass('active') - .find('> .dropdown-menu > .active') - .removeClass('active') - - element.addClass('active') - - if (transition) { - element[0].offsetWidth // reflow for transition - element.addClass('in') - } else { - element.removeClass('fade') - } - - if ( element.parent('.dropdown-menu') ) { - element.closest('li.dropdown').addClass('active') - } - - callback && callback() - } - - transition ? - $active.one($.support.transition.end, next) : - next() - - $active.removeClass('in') - } - } - - - /* TAB PLUGIN DEFINITION - * ===================== */ - - var old = $.fn.tab - - $.fn.tab = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tab') - if (!data) $this.data('tab', (data = new Tab(this))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tab.Constructor = Tab - - - /* TAB NO CONFLICT - * =============== */ - - $.fn.tab.noConflict = function () { - $.fn.tab = old - return this - } - - - /* TAB DATA-API - * ============ */ - - $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { - e.preventDefault() - $(this).tab('show') - }) - -}(window.jQuery);/* ============================================================= - * bootstrap-typeahead.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#typeahead - * ============================================================= - * Copyright 2012 Twitter, Inc. - * - * 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. - * ============================================================ */ - - -!function($){ - - "use strict"; // jshint ;_; - - - /* TYPEAHEAD PUBLIC CLASS DEFINITION - * ================================= */ - - var Typeahead = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, $.fn.typeahead.defaults, options) - this.matcher = this.options.matcher || this.matcher - this.sorter = this.options.sorter || this.sorter - this.highlighter = this.options.highlighter || this.highlighter - this.updater = this.options.updater || this.updater - this.source = this.options.source - this.$menu = $(this.options.menu) - this.shown = false - this.listen() - } - - Typeahead.prototype = { - - constructor: Typeahead - - , select: function () { - var val = this.$menu.find('.active').attr('data-value') - this.$element - .val(this.updater(val)) - .change() - return this.hide() - } - - , updater: function (item) { - return item - } - - , show: function () { - var pos = $.extend({}, this.$element.position(), { - height: this.$element[0].offsetHeight - }) - - this.$menu - .insertAfter(this.$element) - .css({ - top: pos.top + pos.height - , left: pos.left - }) - .show() - - this.shown = true - return this - } - - , hide: function () { - this.$menu.hide() - this.shown = false - return this - } - - , lookup: function (event) { - var items - - this.query = this.$element.val() - - if (!this.query || this.query.length < this.options.minLength) { - return this.shown ? this.hide() : this - } - - items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source - - return items ? this.process(items) : this - } - - , process: function (items) { - var that = this - - items = $.grep(items, function (item) { - return that.matcher(item) - }) - - items = this.sorter(items) - - if (!items.length) { - return this.shown ? this.hide() : this - } - - return this.render(items.slice(0, this.options.items)).show() - } - - , matcher: function (item) { - return ~item.toLowerCase().indexOf(this.query.toLowerCase()) - } - - , sorter: function (items) { - var beginswith = [] - , caseSensitive = [] - , caseInsensitive = [] - , item - - while (item = items.shift()) { - if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) - else if (~item.indexOf(this.query)) caseSensitive.push(item) - else caseInsensitive.push(item) - } - - return beginswith.concat(caseSensitive, caseInsensitive) - } - - , highlighter: function (item) { - var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&') - return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { - return '<strong>' + match + '</strong>' - }) - } - - , render: function (items) { - var that = this - - items = $(items).map(function (i, item) { - i = $(that.options.item).attr('data-value', item) - i.find('a').html(that.highlighter(item)) - return i[0] - }) - - items.first().addClass('active') - this.$menu.html(items) - return this - } - - , next: function (event) { - var active = this.$menu.find('.active').removeClass('active') - , next = active.next() - - if (!next.length) { - next = $(this.$menu.find('li')[0]) - } - - next.addClass('active') - } - - , prev: function (event) { - var active = this.$menu.find('.active').removeClass('active') - , prev = active.prev() - - if (!prev.length) { - prev = this.$menu.find('li').last() - } - - prev.addClass('active') - } - - , listen: function () { - this.$element - .on('blur', $.proxy(this.blur, this)) - .on('keypress', $.proxy(this.keypress, this)) - .on('keyup', $.proxy(this.keyup, this)) - - if (this.eventSupported('keydown')) { - this.$element.on('keydown', $.proxy(this.keydown, this)) - } - - this.$menu - .on('click', $.proxy(this.click, this)) - .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) - } - - , eventSupported: function(eventName) { - var isSupported = eventName in this.$element - if (!isSupported) { - this.$element.setAttribute(eventName, 'return;') - isSupported = typeof this.$element[eventName] === 'function' - } - return isSupported - } - - , move: function (e) { - if (!this.shown) return - - switch(e.keyCode) { - case 9: // tab - case 13: // enter - case 27: // escape - e.preventDefault() - break - - case 38: // up arrow - e.preventDefault() - this.prev() - break - - case 40: // down arrow - e.preventDefault() - this.next() - break - } - - e.stopPropagation() - } - - , keydown: function (e) { - this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]) - this.move(e) - } - - , keypress: function (e) { - if (this.suppressKeyPressRepeat) return - this.move(e) - } - - , keyup: function (e) { - switch(e.keyCode) { - case 40: // down arrow - case 38: // up arrow - case 16: // shift - case 17: // ctrl - case 18: // alt - break - - case 9: // tab - case 13: // enter - if (!this.shown) return - this.select() - break - - case 27: // escape - if (!this.shown) return - this.hide() - break - - default: - this.lookup() - } - - e.stopPropagation() - e.preventDefault() - } - - , blur: function (e) { - var that = this - setTimeout(function () { that.hide() }, 150) - } - - , click: function (e) { - e.stopPropagation() - e.preventDefault() - this.select() - } - - , mouseenter: function (e) { - this.$menu.find('.active').removeClass('active') - $(e.currentTarget).addClass('active') - } - - } - - - /* TYPEAHEAD PLUGIN DEFINITION - * =========================== */ - - var old = $.fn.typeahead - - $.fn.typeahead = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('typeahead') - , options = typeof option == 'object' && option - if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.typeahead.defaults = { - source: [] - , items: 8 - , menu: '<ul class="typeahead dropdown-menu"></ul>' - , item: '<li><a href="#"></a></li>' - , minLength: 1 - } - - $.fn.typeahead.Constructor = Typeahead - - - /* TYPEAHEAD NO CONFLICT - * =================== */ - - $.fn.typeahead.noConflict = function () { - $.fn.typeahead = old - return this - } - - - /* TYPEAHEAD DATA-API - * ================== */ - - $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { - var $this = $(this) - if ($this.data('typeahead')) return - e.preventDefault() - $this.typeahead($this.data()) - }) - -}(window.jQuery); -/* ========================================================== - * bootstrap-affix.js v2.2.2 - * http://twitter.github.com/bootstrap/javascript.html#affix - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * 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. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* AFFIX CLASS DEFINITION - * ====================== */ - - var Affix = function (element, options) { - this.options = $.extend({}, $.fn.affix.defaults, options) - this.$window = $(window) - .on('scroll.affix.data-api', $.proxy(this.checkPosition, this)) - .on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this)) - this.$element = $(element) - this.checkPosition() - } - - Affix.prototype.checkPosition = function () { - if (!this.$element.is(':visible')) return - - var scrollHeight = $(document).height() - , scrollTop = this.$window.scrollTop() - , position = this.$element.offset() - , offset = this.options.offset - , offsetBottom = offset.bottom - , offsetTop = offset.top - , reset = 'affix affix-top affix-bottom' - , affix - - if (typeof offset != 'object') offsetBottom = offsetTop = offset - if (typeof offsetTop == 'function') offsetTop = offset.top() - if (typeof offsetBottom == 'function') offsetBottom = offset.bottom() - - affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? - false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? - 'bottom' : offsetTop != null && scrollTop <= offsetTop ? - 'top' : false - - if (this.affixed === affix) return - - this.affixed = affix - this.unpin = affix == 'bottom' ? position.top - scrollTop : null - - this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : '')) - } - - - /* AFFIX PLUGIN DEFINITION - * ======================= */ - - var old = $.fn.affix - - $.fn.affix = function (option) { - return this.each(function () { - var $this = $(this) - , data = $this.data('affix') - , options = typeof option == 'object' && option - if (!data) $this.data('affix', (data = new Affix(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.affix.Constructor = Affix - - $.fn.affix.defaults = { - offset: 0 - } - - - /* AFFIX NO CONFLICT - * ================= */ - - $.fn.affix.noConflict = function () { - $.fn.affix = old - return this - } - - - /* AFFIX DATA-API - * ============== */ - - $(window).on('load', function () { - $('[data-spy="affix"]').each(function () { - var $spy = $(this) - , data = $spy.data() - - data.offset = data.offset || {} - - data.offsetBottom && (data.offset.bottom = data.offsetBottom) - data.offsetTop && (data.offset.top = data.offsetTop) - - $spy.affix(data) - }) - }) - - -}(window.jQuery);
\ No newline at end of file diff --git a/hyperkitty/static/js/libs/bootstrap.min.js b/hyperkitty/static/js/libs/bootstrap.min.js deleted file mode 100644 index 6eeb15c..0000000 --- a/hyperkitty/static/js/libs/bootstrap.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! -* Bootstrap.js by @fat & @mdo -* Copyright 2012 Twitter, Inc. -* http://www.apache.org/licenses/LICENSE-2.0.txt -*/ -!function($){"use strict";$(function(){$.support.transition=function(){var transitionEnd=function(){var name,el=document.createElement("bootstrap"),transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(name in transEndEventNames)if(void 0!==el.style[name])return transEndEventNames[name]}();return transitionEnd&&{end:transitionEnd}}()})}(window.jQuery),!function($){"use strict";var dismiss='[data-dismiss="alert"]',Alert=function(el){$(el).on("click",dismiss,this.close)};Alert.prototype.close=function(e){function removeElement(){$parent.trigger("closed").remove()}var $parent,$this=$(this),selector=$this.attr("data-target");selector||(selector=$this.attr("href"),selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,"")),$parent=$(selector),e&&e.preventDefault(),$parent.length||($parent=$this.hasClass("alert")?$this:$this.parent()),$parent.trigger(e=$.Event("close")),e.isDefaultPrevented()||($parent.removeClass("in"),$.support.transition&&$parent.hasClass("fade")?$parent.on($.support.transition.end,removeElement):removeElement())};var old=$.fn.alert;$.fn.alert=function(option){return this.each(function(){var $this=$(this),data=$this.data("alert");data||$this.data("alert",data=new Alert(this)),"string"==typeof option&&data[option].call($this)})},$.fn.alert.Constructor=Alert,$.fn.alert.noConflict=function(){return $.fn.alert=old,this},$(document).on("click.alert.data-api",dismiss,Alert.prototype.close)}(window.jQuery),!function($){"use strict";var Button=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.button.defaults,options)};Button.prototype.setState=function(state){var d="disabled",$el=this.$element,data=$el.data(),val=$el.is("input")?"val":"html";state+="Text",data.resetText||$el.data("resetText",$el[val]()),$el[val](data[state]||this.options[state]),setTimeout(function(){"loadingText"==state?$el.addClass(d).attr(d,d):$el.removeClass(d).removeAttr(d)},0)},Button.prototype.toggle=function(){var $parent=this.$element.closest('[data-toggle="buttons-radio"]');$parent&&$parent.find(".active").removeClass("active"),this.$element.toggleClass("active")};var old=$.fn.button;$.fn.button=function(option){return this.each(function(){var $this=$(this),data=$this.data("button"),options="object"==typeof option&&option;data||$this.data("button",data=new Button(this,options)),"toggle"==option?data.toggle():option&&data.setState(option)})},$.fn.button.defaults={loadingText:"loading..."},$.fn.button.Constructor=Button,$.fn.button.noConflict=function(){return $.fn.button=old,this},$(document).on("click.button.data-api","[data-toggle^=button]",function(e){var $btn=$(e.target);$btn.hasClass("btn")||($btn=$btn.closest(".btn")),$btn.button("toggle")})}(window.jQuery),!function($){"use strict";var Carousel=function(element,options){this.$element=$(element),this.options=options,"hover"==this.options.pause&&this.$element.on("mouseenter",$.proxy(this.pause,this)).on("mouseleave",$.proxy(this.cycle,this))};Carousel.prototype={cycle:function(e){return e||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval($.proxy(this.next,this),this.options.interval)),this},to:function(pos){var $active=this.$element.find(".item.active"),children=$active.parent().children(),activePos=children.index($active),that=this;if(!(pos>children.length-1||0>pos))return this.sliding?this.$element.one("slid",function(){that.to(pos)}):activePos==pos?this.pause().cycle():this.slide(pos>activePos?"next":"prev",$(children[pos]))},pause:function(e){return e||(this.paused=!0),this.$element.find(".next, .prev").length&&$.support.transition.end&&(this.$element.trigger($.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){return this.sliding?void 0:this.slide("next")},prev:function(){return this.sliding?void 0:this.slide("prev")},slide:function(type,next){var e,$active=this.$element.find(".item.active"),$next=next||$active[type](),isCycling=this.interval,direction="next"==type?"left":"right",fallback="next"==type?"first":"last",that=this;if(this.sliding=!0,isCycling&&this.pause(),$next=$next.length?$next:this.$element.find(".item")[fallback](),e=$.Event("slide",{relatedTarget:$next[0]}),!$next.hasClass("active")){if($.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(e),e.isDefaultPrevented())return;$next.addClass(type),$next[0].offsetWidth,$active.addClass(direction),$next.addClass(direction),this.$element.one($.support.transition.end,function(){$next.removeClass([type,direction].join(" ")).addClass("active"),$active.removeClass(["active",direction].join(" ")),that.sliding=!1,setTimeout(function(){that.$element.trigger("slid")},0)})}else{if(this.$element.trigger(e),e.isDefaultPrevented())return;$active.removeClass("active"),$next.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return isCycling&&this.cycle(),this}}};var old=$.fn.carousel;$.fn.carousel=function(option){return this.each(function(){var $this=$(this),data=$this.data("carousel"),options=$.extend({},$.fn.carousel.defaults,"object"==typeof option&&option),action="string"==typeof option?option:options.slide;data||$this.data("carousel",data=new Carousel(this,options)),"number"==typeof option?data.to(option):action?data[action]():options.interval&&data.cycle()})},$.fn.carousel.defaults={interval:5e3,pause:"hover"},$.fn.carousel.Constructor=Carousel,$.fn.carousel.noConflict=function(){return $.fn.carousel=old,this},$(document).on("click.carousel.data-api","[data-slide]",function(e){var href,$this=$(this),$target=$($this.attr("data-target")||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,"")),options=$.extend({},$target.data(),$this.data());$target.carousel(options),e.preventDefault()})}(window.jQuery),!function($){"use strict";var Collapse=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.collapse.defaults,options),this.options.parent&&(this.$parent=$(this.options.parent)),this.options.toggle&&this.toggle()};Collapse.prototype={constructor:Collapse,dimension:function(){var hasWidth=this.$element.hasClass("width");return hasWidth?"width":"height"},show:function(){var dimension,scroll,actives,hasData;if(!this.transitioning){if(dimension=this.dimension(),scroll=$.camelCase(["scroll",dimension].join("-")),actives=this.$parent&&this.$parent.find("> .accordion-group > .in"),actives&&actives.length){if(hasData=actives.data("collapse"),hasData&&hasData.transitioning)return;actives.collapse("hide"),hasData||actives.data("collapse",null)}this.$element[dimension](0),this.transition("addClass",$.Event("show"),"shown"),$.support.transition&&this.$element[dimension](this.$element[0][scroll])}},hide:function(){var dimension;this.transitioning||(dimension=this.dimension(),this.reset(this.$element[dimension]()),this.transition("removeClass",$.Event("hide"),"hidden"),this.$element[dimension](0))},reset:function(size){var dimension=this.dimension();return this.$element.removeClass("collapse")[dimension](size||"auto")[0].offsetWidth,this.$element[null!==size?"addClass":"removeClass"]("collapse"),this},transition:function(method,startEvent,completeEvent){var that=this,complete=function(){"show"==startEvent.type&&that.reset(),that.transitioning=0,that.$element.trigger(completeEvent)};this.$element.trigger(startEvent),startEvent.isDefaultPrevented()||(this.transitioning=1,this.$element[method]("in"),$.support.transition&&this.$element.hasClass("collapse")?this.$element.one($.support.transition.end,complete):complete())},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var old=$.fn.collapse;$.fn.collapse=function(option){return this.each(function(){var $this=$(this),data=$this.data("collapse"),options="object"==typeof option&&option;data||$this.data("collapse",data=new Collapse(this,options)),"string"==typeof option&&data[option]()})},$.fn.collapse.defaults={toggle:!0},$.fn.collapse.Constructor=Collapse,$.fn.collapse.noConflict=function(){return $.fn.collapse=old,this},$(document).on("click.collapse.data-api","[data-toggle=collapse]",function(e){var href,$this=$(this),target=$this.attr("data-target")||e.preventDefault()||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,""),option=$(target).data("collapse")?"toggle":$this.data();$this[$(target).hasClass("in")?"addClass":"removeClass"]("collapsed"),$(target).collapse(option)})}(window.jQuery),!function($){"use strict";function clearMenus(){$(toggle).each(function(){getParent($(this)).removeClass("open")})}function getParent($this){var $parent,selector=$this.attr("data-target");return selector||(selector=$this.attr("href"),selector=selector&&/#/.test(selector)&&selector.replace(/.*(?=#[^\s]*$)/,"")),$parent=$(selector),$parent.length||($parent=$this.parent()),$parent}var toggle="[data-toggle=dropdown]",Dropdown=function(element){var $el=$(element).on("click.dropdown.data-api",this.toggle);$("html").on("click.dropdown.data-api",function(){$el.parent().removeClass("open")})};Dropdown.prototype={constructor:Dropdown,toggle:function(){var $parent,isActive,$this=$(this);if(!$this.is(".disabled, :disabled"))return $parent=getParent($this),isActive=$parent.hasClass("open"),clearMenus(),isActive||$parent.toggleClass("open"),$this.focus(),!1},keydown:function(e){var $this,$items,$parent,isActive,index;if(/(38|40|27)/.test(e.keyCode)&&($this=$(this),e.preventDefault(),e.stopPropagation(),!$this.is(".disabled, :disabled"))){if($parent=getParent($this),isActive=$parent.hasClass("open"),!isActive||isActive&&27==e.keyCode)return $this.click();$items=$("[role=menu] li:not(.divider):visible a",$parent),$items.length&&(index=$items.index($items.filter(":focus")),38==e.keyCode&&index>0&&index--,40==e.keyCode&&$items.length-1>index&&index++,~index||(index=0),$items.eq(index).focus())}}};var old=$.fn.dropdown;$.fn.dropdown=function(option){return this.each(function(){var $this=$(this),data=$this.data("dropdown");data||$this.data("dropdown",data=new Dropdown(this)),"string"==typeof option&&data[option].call($this)})},$.fn.dropdown.Constructor=Dropdown,$.fn.dropdown.noConflict=function(){return $.fn.dropdown=old,this},$(document).on("click.dropdown.data-api touchstart.dropdown.data-api",clearMenus).on("click.dropdown touchstart.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("touchstart.dropdown.data-api",".dropdown-menu",function(e){e.stopPropagation()}).on("click.dropdown.data-api touchstart.dropdown.data-api",toggle,Dropdown.prototype.toggle).on("keydown.dropdown.data-api touchstart.dropdown.data-api",toggle+", [role=menu]",Dropdown.prototype.keydown)}(window.jQuery),!function($){"use strict";var Modal=function(element,options){this.options=options,this.$element=$(element).delegate('[data-dismiss="modal"]',"click.dismiss.modal",$.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};Modal.prototype={constructor:Modal,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var that=this,e=$.Event("show");this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.backdrop(function(){var transition=$.support.transition&&that.$element.hasClass("fade");that.$element.parent().length||that.$element.appendTo(document.body),that.$element.show(),transition&&that.$element[0].offsetWidth,that.$element.addClass("in").attr("aria-hidden",!1),that.enforceFocus(),transition?that.$element.one($.support.transition.end,function(){that.$element.focus().trigger("shown")}):that.$element.focus().trigger("shown")}))},hide:function(e){e&&e.preventDefault(),e=$.Event("hide"),this.$element.trigger(e),this.isShown&&!e.isDefaultPrevented()&&(this.isShown=!1,this.escape(),$(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),$.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal())},enforceFocus:function(){var that=this;$(document).on("focusin.modal",function(e){that.$element[0]===e.target||that.$element.has(e.target).length||that.$element.focus()})},escape:function(){var that=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(e){27==e.which&&that.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var that=this,timeout=setTimeout(function(){that.$element.off($.support.transition.end),that.hideModal()},500);this.$element.one($.support.transition.end,function(){clearTimeout(timeout),that.hideModal()})},hideModal:function(){this.$element.hide().trigger("hidden"),this.backdrop()},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(callback){var animate=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var doAnimate=$.support.transition&&animate;this.$backdrop=$('<div class="modal-backdrop '+animate+'" />').appendTo(document.body),this.$backdrop.click("static"==this.options.backdrop?$.proxy(this.$element[0].focus,this.$element[0]):$.proxy(this.hide,this)),doAnimate&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),doAnimate?this.$backdrop.one($.support.transition.end,callback):callback()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),$.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one($.support.transition.end,$.proxy(this.removeBackdrop,this)):this.removeBackdrop()):callback&&callback()}};var old=$.fn.modal;$.fn.modal=function(option){return this.each(function(){var $this=$(this),data=$this.data("modal"),options=$.extend({},$.fn.modal.defaults,$this.data(),"object"==typeof option&&option);data||$this.data("modal",data=new Modal(this,options)),"string"==typeof option?data[option]():options.show&&data.show()})},$.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},$.fn.modal.Constructor=Modal,$.fn.modal.noConflict=function(){return $.fn.modal=old,this},$(document).on("click.modal.data-api",'[data-toggle="modal"]',function(e){var $this=$(this),href=$this.attr("href"),$target=$($this.attr("data-target")||href&&href.replace(/.*(?=#[^\s]+$)/,"")),option=$target.data("modal")?"toggle":$.extend({remote:!/#/.test(href)&&href},$target.data(),$this.data());e.preventDefault(),$target.modal(option).one("hide",function(){$this.focus()})})}(window.jQuery),!function($){"use strict";var Tooltip=function(element,options){this.init("tooltip",element,options)};Tooltip.prototype={constructor:Tooltip,init:function(type,element,options){var eventIn,eventOut;this.type=type,this.$element=$(element),this.options=this.getOptions(options),this.enabled=!0,"click"==this.options.trigger?this.$element.on("click."+this.type,this.options.selector,$.proxy(this.toggle,this)):"manual"!=this.options.trigger&&(eventIn="hover"==this.options.trigger?"mouseenter":"focus",eventOut="hover"==this.options.trigger?"mouseleave":"blur",this.$element.on(eventIn+"."+this.type,this.options.selector,$.proxy(this.enter,this)),this.$element.on(eventOut+"."+this.type,this.options.selector,$.proxy(this.leave,this))),this.options.selector?this._options=$.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(options){return options=$.extend({},$.fn[this.type].defaults,options,this.$element.data()),options.delay&&"number"==typeof options.delay&&(options.delay={show:options.delay,hide:options.delay}),options},enter:function(e){var self=$(e.currentTarget)[this.type](this._options).data(this.type);return self.options.delay&&self.options.delay.show?(clearTimeout(this.timeout),self.hoverState="in",this.timeout=setTimeout(function(){"in"==self.hoverState&&self.show()},self.options.delay.show),void 0):self.show()},leave:function(e){var self=$(e.currentTarget)[this.type](this._options).data(this.type);return this.timeout&&clearTimeout(this.timeout),self.options.delay&&self.options.delay.hide?(self.hoverState="out",this.timeout=setTimeout(function(){"out"==self.hoverState&&self.hide()},self.options.delay.hide),void 0):self.hide()},show:function(){var $tip,inside,pos,actualWidth,actualHeight,placement,tp;if(this.hasContent()&&this.enabled){switch($tip=this.tip(),this.setContent(),this.options.animation&&$tip.addClass("fade"),placement="function"==typeof this.options.placement?this.options.placement.call(this,$tip[0],this.$element[0]):this.options.placement,inside=/in/.test(placement),$tip.detach().css({top:0,left:0,display:"block"}).insertAfter(this.$element),pos=this.getPosition(inside),actualWidth=$tip[0].offsetWidth,actualHeight=$tip[0].offsetHeight,inside?placement.split(" ")[1]:placement){case"bottom":tp={top:pos.top+pos.height,left:pos.left+pos.width/2-actualWidth/2};break;case"top":tp={top:pos.top-actualHeight,left:pos.left+pos.width/2-actualWidth/2};break;case"left":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left-actualWidth};break;case"right":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left+pos.width}}$tip.offset(tp).addClass(placement).addClass("in")}},setContent:function(){var $tip=this.tip(),title=this.getTitle();$tip.find(".tooltip-inner")[this.options.html?"html":"text"](title),$tip.removeClass("fade in top bottom left right")},hide:function(){function removeWithAnimation(){var timeout=setTimeout(function(){$tip.off($.support.transition.end).detach()},500);$tip.one($.support.transition.end,function(){clearTimeout(timeout),$tip.detach()})}var $tip=this.tip();return $tip.removeClass("in"),$.support.transition&&this.$tip.hasClass("fade")?removeWithAnimation():$tip.detach(),this},fixTitle:function(){var $e=this.$element;($e.attr("title")||"string"!=typeof $e.attr("data-original-title"))&&$e.attr("data-original-title",$e.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(inside){return $.extend({},inside?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var title,$e=this.$element,o=this.options;return title=$e.attr("data-original-title")||("function"==typeof o.title?o.title.call($e[0]):o.title)},tip:function(){return this.$tip=this.$tip||$(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(e){var self=$(e.currentTarget)[this.type](this._options).data(this.type);self[self.tip().hasClass("in")?"hide":"show"]()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var old=$.fn.tooltip;$.fn.tooltip=function(option){return this.each(function(){var $this=$(this),data=$this.data("tooltip"),options="object"==typeof option&&option;data||$this.data("tooltip",data=new Tooltip(this,options)),"string"==typeof option&&data[option]()})},$.fn.tooltip.Constructor=Tooltip,$.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0,html:!1},$.fn.tooltip.noConflict=function(){return $.fn.tooltip=old,this}}(window.jQuery),!function($){"use strict";var Popover=function(element,options){this.init("popover",element,options)};Popover.prototype=$.extend({},$.fn.tooltip.Constructor.prototype,{constructor:Popover,setContent:function(){var $tip=this.tip(),title=this.getTitle(),content=this.getContent();$tip.find(".popover-title")[this.options.html?"html":"text"](title),$tip.find(".popover-content")[this.options.html?"html":"text"](content),$tip.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var content,$e=this.$element,o=this.options;return content=$e.attr("data-content")||("function"==typeof o.content?o.content.call($e[0]):o.content)},tip:function(){return this.$tip||(this.$tip=$(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var old=$.fn.popover;$.fn.popover=function(option){return this.each(function(){var $this=$(this),data=$this.data("popover"),options="object"==typeof option&&option;data||$this.data("popover",data=new Popover(this,options)),"string"==typeof option&&data[option]()})},$.fn.popover.Constructor=Popover,$.fn.popover.defaults=$.extend({},$.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"></div></div></div>'}),$.fn.popover.noConflict=function(){return $.fn.popover=old,this}}(window.jQuery),!function($){"use strict";function ScrollSpy(element,options){var href,process=$.proxy(this.process,this),$element=$(element).is("body")?$(window):$(element);this.options=$.extend({},$.fn.scrollspy.defaults,options),this.$scrollElement=$element.on("scroll.scroll-spy.data-api",process),this.selector=(this.options.target||(href=$(element).attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=$("body"),this.refresh(),this.process()}ScrollSpy.prototype={constructor:ScrollSpy,refresh:function(){var $targets,self=this;this.offsets=$([]),this.targets=$([]),$targets=this.$body.find(this.selector).map(function(){var $el=$(this),href=$el.data("target")||$el.attr("href"),$href=/^#\w/.test(href)&&$(href);return $href&&$href.length&&[[$href.position().top+self.$scrollElement.scrollTop(),href]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){self.offsets.push(this[0]),self.targets.push(this[1])})},process:function(){var i,scrollTop=this.$scrollElement.scrollTop()+this.options.offset,scrollHeight=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,maxScroll=scrollHeight-this.$scrollElement.height(),offsets=this.offsets,targets=this.targets,activeTarget=this.activeTarget;if(scrollTop>=maxScroll)return activeTarget!=(i=targets.last()[0])&&this.activate(i);for(i=offsets.length;i--;)activeTarget!=targets[i]&&scrollTop>=offsets[i]&&(!offsets[i+1]||offsets[i+1]>=scrollTop)&&this.activate(targets[i])},activate:function(target){var active,selector;this.activeTarget=target,$(this.selector).parent(".active").removeClass("active"),selector=this.selector+'[data-target="'+target+'"],'+this.selector+'[href="'+target+'"]',active=$(selector).parent("li").addClass("active"),active.parent(".dropdown-menu").length&&(active=active.closest("li.dropdown").addClass("active")),active.trigger("activate")}};var old=$.fn.scrollspy;$.fn.scrollspy=function(option){return this.each(function(){var $this=$(this),data=$this.data("scrollspy"),options="object"==typeof option&&option;data||$this.data("scrollspy",data=new ScrollSpy(this,options)),"string"==typeof option&&data[option]()})},$.fn.scrollspy.Constructor=ScrollSpy,$.fn.scrollspy.defaults={offset:10},$.fn.scrollspy.noConflict=function(){return $.fn.scrollspy=old,this},$(window).on("load",function(){$('[data-spy="scroll"]').each(function(){var $spy=$(this);$spy.scrollspy($spy.data())})})}(window.jQuery),!function($){"use strict";var Tab=function(element){this.element=$(element)};Tab.prototype={constructor:Tab,show:function(){var previous,$target,e,$this=this.element,$ul=$this.closest("ul:not(.dropdown-menu)"),selector=$this.attr("data-target");selector||(selector=$this.attr("href"),selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,"")),$this.parent("li").hasClass("active")||(previous=$ul.find(".active:last a")[0],e=$.Event("show",{relatedTarget:previous}),$this.trigger(e),e.isDefaultPrevented()||($target=$(selector),this.activate($this.parent("li"),$ul),this.activate($target,$target.parent(),function(){$this.trigger({type:"shown",relatedTarget:previous})})))},activate:function(element,container,callback){function next(){$active.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),element.addClass("active"),transition?(element[0].offsetWidth,element.addClass("in")):element.removeClass("fade"),element.parent(".dropdown-menu")&&element.closest("li.dropdown").addClass("active"),callback&&callback()}var $active=container.find("> .active"),transition=callback&&$.support.transition&&$active.hasClass("fade");transition?$active.one($.support.transition.end,next):next(),$active.removeClass("in")}};var old=$.fn.tab;$.fn.tab=function(option){return this.each(function(){var $this=$(this),data=$this.data("tab");data||$this.data("tab",data=new Tab(this)),"string"==typeof option&&data[option]()})},$.fn.tab.Constructor=Tab,$.fn.tab.noConflict=function(){return $.fn.tab=old,this},$(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(e){e.preventDefault(),$(this).tab("show")})}(window.jQuery),!function($){"use strict";var Typeahead=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.typeahead.defaults,options),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=$(this.options.menu),this.shown=!1,this.listen()};Typeahead.prototype={constructor:Typeahead,select:function(){var val=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(val)).change(),this.hide()},updater:function(item){return item},show:function(){var pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:pos.top+pos.height,left:pos.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(){var items;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(items=$.isFunction(this.source)?this.source(this.query,$.proxy(this.process,this)):this.source,items?this.process(items):this)},process:function(items){var that=this;return items=$.grep(items,function(item){return that.matcher(item)}),items=this.sorter(items),items.length?this.render(items.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(item){return~item.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(items){for(var item,beginswith=[],caseSensitive=[],caseInsensitive=[];item=items.shift();)item.toLowerCase().indexOf(this.query.toLowerCase())?~item.indexOf(this.query)?caseSensitive.push(item):caseInsensitive.push(item):beginswith.push(item);return beginswith.concat(caseSensitive,caseInsensitive)},highlighter:function(item){var query=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return item.replace(RegExp("("+query+")","ig"),function($1,match){return"<strong>"+match+"</strong>"})},render:function(items){var that=this;return items=$(items).map(function(i,item){return i=$(that.options.item).attr("data-value",item),i.find("a").html(that.highlighter(item)),i[0]}),items.first().addClass("active"),this.$menu.html(items),this},next:function(){var active=this.$menu.find(".active").removeClass("active"),next=active.next();next.length||(next=$(this.$menu.find("li")[0])),next.addClass("active")},prev:function(){var active=this.$menu.find(".active").removeClass("active"),prev=active.prev();prev.length||(prev=this.$menu.find("li").last()),prev.addClass("active")},listen:function(){this.$element.on("blur",$.proxy(this.blur,this)).on("keypress",$.proxy(this.keypress,this)).on("keyup",$.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",$.proxy(this.keydown,this)),this.$menu.on("click",$.proxy(this.click,this)).on("mouseenter","li",$.proxy(this.mouseenter,this))},eventSupported:function(eventName){var isSupported=eventName in this.$element;return isSupported||(this.$element.setAttribute(eventName,"return;"),isSupported="function"==typeof this.$element[eventName]),isSupported},move:function(e){if(this.shown){switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()}},keydown:function(e){this.suppressKeyPressRepeat=~$.inArray(e.keyCode,[40,38,9,13,27]),this.move(e)},keypress:function(e){this.suppressKeyPressRepeat||this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(){var that=this;setTimeout(function(){that.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(e){this.$menu.find(".active").removeClass("active"),$(e.currentTarget).addClass("active")}};var old=$.fn.typeahead;$.fn.typeahead=function(option){return this.each(function(){var $this=$(this),data=$this.data("typeahead"),options="object"==typeof option&&option;data||$this.data("typeahead",data=new Typeahead(this,options)),"string"==typeof option&&data[option]()})},$.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},$.fn.typeahead.Constructor=Typeahead,$.fn.typeahead.noConflict=function(){return $.fn.typeahead=old,this},$(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(e){var $this=$(this);$this.data("typeahead")||(e.preventDefault(),$this.typeahead($this.data()))})}(window.jQuery),!function($){"use strict";var Affix=function(element,options){this.options=$.extend({},$.fn.affix.defaults,options),this.$window=$(window).on("scroll.affix.data-api",$.proxy(this.checkPosition,this)).on("click.affix.data-api",$.proxy(function(){setTimeout($.proxy(this.checkPosition,this),1)},this)),this.$element=$(element),this.checkPosition()};Affix.prototype.checkPosition=function(){if(this.$element.is(":visible")){var affix,scrollHeight=$(document).height(),scrollTop=this.$window.scrollTop(),position=this.$element.offset(),offset=this.options.offset,offsetBottom=offset.bottom,offsetTop=offset.top,reset="affix affix-top affix-bottom";"object"!=typeof offset&&(offsetBottom=offsetTop=offset),"function"==typeof offsetTop&&(offsetTop=offset.top()),"function"==typeof offsetBottom&&(offsetBottom=offset.bottom()),affix=null!=this.unpin&&scrollTop+this.unpin<=position.top?!1:null!=offsetBottom&&position.top+this.$element.height()>=scrollHeight-offsetBottom?"bottom":null!=offsetTop&&offsetTop>=scrollTop?"top":!1,this.affixed!==affix&&(this.affixed=affix,this.unpin="bottom"==affix?position.top-scrollTop:null,this.$element.removeClass(reset).addClass("affix"+(affix?"-"+affix:"")))}};var old=$.fn.affix;$.fn.affix=function(option){return this.each(function(){var $this=$(this),data=$this.data("affix"),options="object"==typeof option&&option;data||$this.data("affix",data=new Affix(this,options)),"string"==typeof option&&data[option]()})},$.fn.affix.Constructor=Affix,$.fn.affix.defaults={offset:0},$.fn.affix.noConflict=function(){return $.fn.affix=old,this},$(window).on("load",function(){$('[data-spy="affix"]').each(function(){var $spy=$(this),data=$spy.data();data.offset=data.offset||{},data.offsetBottom&&(data.offset.bottom=data.offsetBottom),data.offsetTop&&(data.offset.top=data.offsetTop),$spy.affix(data)})})}(window.jQuery);
\ No newline at end of file diff --git a/hyperkitty/static/js/libs/jquery-1.8.3.min.js b/hyperkitty/static/js/libs/jquery-1.8.3.min.js deleted file mode 100644 index 83589da..0000000 --- a/hyperkitty/static/js/libs/jquery-1.8.3.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v1.8.3 jquery.com | jquery.org/license */
-(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window);
\ No newline at end of file diff --git a/hyperkitty/static/js/libs/jquery-ui-1.9.1.custom.min.js b/hyperkitty/static/js/libs/jquery-ui-1.9.1.custom.min.js deleted file mode 100644 index 67bbcd1..0000000 --- a/hyperkitty/static/js/libs/jquery-ui-1.9.1.custom.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! jQuery UI - v1.9.1 - 2012-11-15 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.accordion.js -* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */ - -(function(e,t){function i(t,n){var r,i,o,u=t.nodeName.toLowerCase();return"area"===u?(r=t.parentNode,i=r.name,!t.href||!i||r.nodeName.toLowerCase()!=="map"?!1:(o=e("img[usemap=#"+i+"]")[0],!!o&&s(o))):(/input|select|textarea|button|object/.test(u)?!t.disabled:"a"===u?t.href||n:n)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().andSelf().filter(function(){return e.css(this,"visibility")==="hidden"}).length}var n=0,r=/^ui-id-\d+$/;e.ui=e.ui||{};if(e.ui.version)return;e.extend(e.ui,{version:"1.9.1",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({_focus:e.fn.focus,focus:function(t,n){return typeof t=="number"?this.each(function(){var r=this;setTimeout(function(){e(r).focus(),n&&n.call(r)},t)}):this._focus.apply(this,arguments)},scrollParent:function(){var t;return e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?t=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):t=this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(n){if(n!==t)return this.css("zIndex",n);if(this.length){var r=e(this[0]),i,s;while(r.length&&r[0]!==document){i=r.css("position");if(i==="absolute"||i==="relative"||i==="fixed"){s=parseInt(r.css("zIndex"),10);if(!isNaN(s)&&s!==0)return s}r=r.parent()}}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++n)})},removeUniqueId:function(){return this.each(function(){r.test(this.id)&&e(this).removeAttr("id")})}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(n,r){function u(t,n,r,s){return e.each(i,function(){n-=parseFloat(e.css(t,"padding"+this))||0,r&&(n-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(n-=parseFloat(e.css(t,"margin"+this))||0)}),n}var i=r==="Width"?["Left","Right"]:["Top","Bottom"],s=r.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+r]=function(n){return n===t?o["inner"+r].call(this):this.each(function(){e(this).css(s,u(this,n)+"px")})},e.fn["outer"+r]=function(t,n){return typeof t!="number"?o["outer"+r].call(this,t):this.each(function(){e(this).css(s,u(this,t,!0,n)+"px")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(n){return!!e.data(n,t)}}):function(t,n,r){return!!e.data(t,r[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var n=e.attr(t,"tabindex"),r=isNaN(n);return(r||n>=0)&&i(t,!r)}}),e(function(){var t=document.body,n=t.appendChild(n=document.createElement("div"));n.offsetHeight,e.extend(n.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),e.support.minHeight=n.offsetHeight===100,e.support.selectstart="onselectstart"in n,t.removeChild(n).style.display="none"}),function(){var t=/msie ([\w.]+)/.exec(navigator.userAgent.toLowerCase())||[];e.ui.ie=t.length?!0:!1,e.ui.ie6=parseFloat(t[1],10)===6}(),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,n,r){var i,s=e.ui[t].prototype;for(i in r)s.plugins[i]=s.plugins[i]||[],s.plugins[i].push([n,r[i]])},call:function(e,t,n){var r,i=e.plugins[t];if(!i||!e.element[0].parentNode||e.element[0].parentNode.nodeType===11)return;for(r=0;r<i.length;r++)e.options[i[r][0]]&&i[r][1].apply(e.element,n)}},contains:e.contains,hasScroll:function(t,n){if(e(t).css("overflow")==="hidden")return!1;var r=n&&n==="left"?"scrollLeft":"scrollTop",i=!1;return t[r]>0?!0:(t[r]=1,i=t[r]>0,t[r]=0,i)},isOverAxis:function(e,t,n){return e>t&&e<t+n},isOver:function(t,n,r,i,s,o){return e.ui.isOverAxis(t,r,s)&&e.ui.isOverAxis(n,i,o)}})})(jQuery);(function(e,t){var n=0,r=Array.prototype.slice,i=e.cleanData;e.cleanData=function(t){for(var n=0,r;(r=t[n])!=null;n++)try{e(r).triggerHandler("remove")}catch(s){}i(t)},e.widget=function(t,n,r){var i,s,o,u,a=t.split(".")[0];t=t.split(".")[1],i=a+"-"+t,r||(r=n,n=e.Widget),e.expr[":"][i.toLowerCase()]=function(t){return!!e.data(t,i)},e[a]=e[a]||{},s=e[a][t],o=e[a][t]=function(e,t){if(!this._createWidget)return new o(e,t);arguments.length&&this._createWidget(e,t)},e.extend(o,s,{version:r.version,_proto:e.extend({},r),_childConstructors:[]}),u=new n,u.options=e.widget.extend({},u.options),e.each(r,function(t,i){e.isFunction(i)&&(r[t]=function(){var e=function(){return n.prototype[t].apply(this,arguments)},r=function(e){return n.prototype[t].apply(this,e)};return function(){var t=this._super,n=this._superApply,s;return this._super=e,this._superApply=r,s=i.apply(this,arguments),this._super=t,this._superApply=n,s}}())}),o.prototype=e.widget.extend(u,{widgetEventPrefix:u.widgetEventPrefix||t},r,{constructor:o,namespace:a,widgetName:t,widgetBaseClass:i,widgetFullName:i}),s?(e.each(s._childConstructors,function(t,n){var r=n.prototype;e.widget(r.namespace+"."+r.widgetName,o,n._proto)}),delete s._childConstructors):n._childConstructors.push(o),e.widget.bridge(t,o)},e.widget.extend=function(n){var i=r.call(arguments,1),s=0,o=i.length,u,a;for(;s<o;s++)for(u in i[s])a=i[s][u],i[s].hasOwnProperty(u)&&a!==t&&(e.isPlainObject(a)?n[u]=e.isPlainObject(n[u])?e.widget.extend({},n[u],a):e.widget.extend({},a):n[u]=a);return n},e.widget.bridge=function(n,i){var s=i.prototype.widgetFullName;e.fn[n]=function(o){var u=typeof o=="string",a=r.call(arguments,1),f=this;return o=!u&&a.length?e.widget.extend.apply(null,[o].concat(a)):o,u?this.each(function(){var r,i=e.data(this,s);if(!i)return e.error("cannot call methods on "+n+" prior to initialization; "+"attempted to call method '"+o+"'");if(!e.isFunction(i[o])||o.charAt(0)==="_")return e.error("no such method '"+o+"' for "+n+" widget instance");r=i[o].apply(i,a);if(r!==i&&r!==t)return f=r&&r.jquery?f.pushStack(r.get()):r,!1}):this.each(function(){var t=e.data(this,s);t?t.option(o||{})._init():new i(o,this)}),f}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,r){r=e(r||this.defaultElement||this)[0],this.element=e(r),this.uuid=n++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),r!==this&&(e.data(r,this.widgetName,this),e.data(r,this.widgetFullName,this),this._on(this.element,{remove:function(e){e.target===r&&this.destroy()}}),this.document=e(r.style?r.ownerDocument:r.document||r),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(n,r){var i=n,s,o,u;if(arguments.length===0)return e.widget.extend({},this.options);if(typeof n=="string"){i={},s=n.split("."),n=s.shift();if(s.length){o=i[n]=e.widget.extend({},this.options[n]);for(u=0;u<s.length-1;u++)o[s[u]]=o[s[u]]||{},o=o[s[u]];n=s.pop();if(r===t)return o[n]===t?null:o[n];o[n]=r}else{if(r===t)return this.options[n]===t?null:this.options[n];i[n]=r}}return this._setOptions(i),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,e==="disabled"&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(t,n){var r,i=this;n?(t=r=e(t),this.bindings=this.bindings.add(t)):(n=t,t=this.element,r=this.widget()),e.each(n,function(n,s){function o(){if(i.options.disabled===!0||e(this).hasClass("ui-state-disabled"))return;return(typeof s=="string"?i[s]:s).apply(i,arguments)}typeof s!="string"&&(o.guid=s.guid=s.guid||o.guid||e.guid++);var u=n.match(/^(\w+)\s*(.*)$/),a=u[1]+i.eventNamespace,f=u[2];f?r.delegate(f,a,o):t.bind(a,o)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function n(){return(typeof e=="string"?r[e]:e).apply(r,arguments)}var r=this;return setTimeout(n,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,n,r){var i,s,o=this.options[t];r=r||{},n=e.Event(n),n.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),n.target=this.element[0],s=n.originalEvent;if(s)for(i in s)i in n||(n[i]=s[i]);return this.element.trigger(n,r),!(e.isFunction(o)&&o.apply(this.element[0],[n].concat(r))===!1||n.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,n){e.Widget.prototype["_"+t]=function(r,i,s){typeof i=="string"&&(i={effect:i});var o,u=i?i===!0||typeof i=="number"?n:i.effect||n:t;i=i||{},typeof i=="number"&&(i={duration:i}),o=!e.isEmptyObject(i),i.complete=s,i.delay&&r.delay(i.delay),o&&e.effects&&(e.effects.effect[u]||e.uiBackCompat!==!1&&e.effects[u])?r[t](i):u!==t&&r[u]?r[u](i.duration,i.easing,s):r.queue(function(n){e(this)[t](),s&&s.call(r[0]),n()})}}),e.uiBackCompat!==!1&&(e.Widget.prototype._getCreateOptions=function(){return e.metadata&&e.metadata.get(this.element[0])[this.widgetName]})})(jQuery);(function(e,t){var n=0,r={},i={};r.height=r.paddingTop=r.paddingBottom=r.borderTopWidth=r.borderBottomWidth="hide",i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="show",e.widget("ui.accordion",{version:"1.9.1",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var t=this.accordionId="ui-accordion-"+(this.element.attr("id")||++n),r=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset"),this.headers=this.element.find(r.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this._hoverable(this.headers),this._focusable(this.headers),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").hide(),!r.collapsible&&(r.active===!1||r.active==null)&&(r.active=0),r.active<0&&(r.active+=this.headers.length),this.active=this._findActive(r.active).addClass("ui-accordion-header-active ui-state-active").toggleClass("ui-corner-all ui-corner-top"),this.active.next().addClass("ui-accordion-content-active").show(),this._createIcons(),this.refresh(),this.element.attr("role","tablist"),this.headers.attr("role","tab").each(function(n){var r=e(this),i=r.attr("id"),s=r.next(),o=s.attr("id");i||(i=t+"-header-"+n,r.attr("id",i)),o||(o=t+"-panel-"+n,s.attr("id",o)),r.attr("aria-controls",o),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._on(this.headers,{keydown:"_keydown"}),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._setupEvents(r.event)},_getCreateEventData:function(){return{header:this.active,content:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("<span>").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),e=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this.options.heightStyle!=="content"&&e.css("height","")},_setOption:function(e,t){if(e==="active"){this._activate(t);return}e==="event"&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),e==="collapsible"&&!t&&this.options.active===!1&&this._activate(0),e==="icons"&&(this._destroyIcons(),t&&this._createIcons()),e==="disabled"&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)},_keydown:function(t){if(t.altKey||t.ctrlKey)return;var n=e.ui.keyCode,r=this.headers.length,i=this.headers.index(t.target),s=!1;switch(t.keyCode){case n.RIGHT:case n.DOWN:s=this.headers[(i+1)%r];break;case n.LEFT:case n.UP:s=this.headers[(i-1+r)%r];break;case n.SPACE:case n.ENTER:this._eventHandler(t);break;case n.HOME:s=this.headers[0];break;case n.END:s=this.headers[r-1]}s&&(e(t.target).attr("tabIndex",-1),e(s).attr("tabIndex",0),s.focus(),t.preventDefault())},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t,n,r=this.options.heightStyle,i=this.element.parent();r==="fill"?(e.support.minHeight||(n=i.css("overflow"),i.css("overflow","hidden")),t=i.height(),this.element.siblings(":visible").each(function(){var n=e(this),r=n.css("position");if(r==="absolute"||r==="fixed")return;t-=n.outerHeight(!0)}),n&&i.css("overflow",n),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):r==="auto"&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).height("").height())}).height(t))},_activate:function(t){var n=this._findActive(t)[0];if(n===this.active[0])return;n=n||this.active[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return typeof t=="number"?this.headers.eq(t):e()},_setupEvents:function(t){var n={};if(!t)return;e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._on(this.headers,n)},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i[0]===r[0],o=s&&n.collapsible,u=o?e():i.next(),a=r.next(),f={oldHeader:r,oldPanel:a,newHeader:o?e():i,newPanel:u};t.preventDefault();if(s&&!n.collapsible||this._trigger("beforeActivate",t,f)===!1)return;n.active=o?!1:this.headers.index(i),this.active=s?e():i,this._toggle(f),r.removeClass("ui-accordion-header-active ui-state-active"),n.icons&&r.children(".ui-accordion-header-icon").removeClass(n.icons.activeHeader).addClass(n.icons.header),s||(i.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),n.icons&&i.children(".ui-accordion-header-icon").removeClass(n.icons.header).addClass(n.icons.activeHeader),i.next().addClass("ui-accordion-content-active"))},_toggle:function(t){var n=t.newPanel,r=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=n,this.prevHide=r,this.options.animate?this._animate(n,r,t):(r.hide(),n.show(),this._toggleComplete(t)),r.attr({"aria-expanded":"false","aria-hidden":"true"}),r.prev().attr("aria-selected","false"),n.length&&r.length?r.prev().attr("tabIndex",-1):n.length&&this.headers.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),n.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(e,t,n){var s,o,u,a=this,f=0,l=e.length&&(!t.length||e.index()<t.index()),c=this.options.animate||{},h=l&&c.down||c,p=function(){a._toggleComplete(n)};typeof h=="number"&&(u=h),typeof h=="string"&&(o=h),o=o||h.easing||c.easing,u=u||h.duration||c.duration;if(!t.length)return e.animate(i,u,o,p);if(!e.length)return t.animate(r,u,o,p);s=e.show().outerHeight(),t.animate(r,{duration:u,easing:o,step:function(e,t){t.now=Math.round(e)}}),e.hide().animate(i,{duration:u,easing:o,complete:p,step:function(e,n){n.now=Math.round(e),n.prop!=="height"?f+=n.now:a.options.heightStyle!=="content"&&(n.now=Math.round(s-t.outerHeight()-f),f=0)}})},_toggleComplete:function(e){var t=e.oldPanel;t.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),t.length&&(t.parent()[0].className=t.parent()[0].className),this._trigger("activate",null,e)}}),e.uiBackCompat!==!1&&(function(e,t){e.extend(t.options,{navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}});var n=t._create;t._create=function(){if(this.options.navigation){var t=this,r=this.element.find(this.options.header),i=r.next(),s=r.add(i).find("a").filter(this.options.navigationFilter)[0];s&&r.add(i).each(function(n){if(e.contains(this,s))return t.options.active=Math.floor(n/2),!1})}n.call(this)}}(jQuery,jQuery.ui.accordion.prototype),function(e,t){e.extend(t.options,{heightStyle:null,autoHeight:!0,clearStyle:!1,fillSpace:!1});var n=t._create,r=t._setOption;e.extend(t,{_create:function(){this.options.heightStyle=this.options.heightStyle||this._mergeHeightStyle(),n.call(this)},_setOption:function(e){if(e==="autoHeight"||e==="clearStyle"||e==="fillSpace")this.options.heightStyle=this._mergeHeightStyle();r.apply(this,arguments)},_mergeHeightStyle:function(){var e=this.options;if(e.fillSpace)return"fill";if(e.clearStyle)return"content";if(e.autoHeight)return"auto"}})}(jQuery,jQuery.ui.accordion.prototype),function(e,t){e.extend(t.options.icons,{activeHeader:null,headerSelected:"ui-icon-triangle-1-s"});var n=t._createIcons;t._createIcons=function(){this.options.icons&&(this.options.icons.activeHeader=this.options.icons.activeHeader||this.options.icons.headerSelected),n.call(this)}}(jQuery,jQuery.ui.accordion.prototype),function(e,t){t.activate=t._activate;var n=t._findActive;t._findActive=function(e){return e===-1&&(e=!1),e&&typeof e!="number"&&(e=this.headers.index(this.headers.filter(e)),e===-1&&(e=!1)),n.call(this,e)}}(jQuery,jQuery.ui.accordion.prototype),jQuery.ui.accordion.prototype.resize=jQuery.ui.accordion.prototype.refresh,function(e,t){e.extend(t.options,{change:null,changestart:null});var n=t._trigger;t._trigger=function(e,t,r){var i=n.apply(this,arguments);return i?(e==="beforeActivate"?i=n.call(this,"changestart",t,{oldHeader:r.oldHeader,oldContent:r.oldPanel,newHeader:r.newHeader,newContent:r.newPanel}):e==="activate"&&(i=n.call(this,"change",t,{oldHeader:r.oldHeader,oldContent:r.oldPanel,newHeader:r.newHeader,newContent:r.newPanel})),i):!1}}(jQuery,jQuery.ui.accordion.prototype),function(e,t){e.extend(t.options,{animate:null,animated:"slide"});var n=t._create;t._create=function(){var e=this.options;e.animate===null&&(e.animated?e.animated==="slide"?e.animate=300:e.animated==="bounceslide"?e.animate={duration:200,down:{easing:"easeOutBounce",duration:1e3}}:e.animate=e.animated:e.animate=!1),n.call(this)}}(jQuery,jQuery.ui.accordion.prototype))})(jQuery);
\ No newline at end of file diff --git a/hyperkitty/static/js/libs/jquery-ui-selection.txt b/hyperkitty/static/js/libs/jquery-ui-selection.txt deleted file mode 100644 index 4a8f33f..0000000 --- a/hyperkitty/static/js/libs/jquery-ui-selection.txt +++ /dev/null @@ -1 +0,0 @@ -Widgets/Accordion diff --git a/hyperkitty/static/js/libs/jquery.expander.js b/hyperkitty/static/js/libs/jquery.expander.js deleted file mode 100644 index 214e5da..0000000 --- a/hyperkitty/static/js/libs/jquery.expander.js +++ /dev/null @@ -1,382 +0,0 @@ -/*! - * jQuery Expander Plugin v1.4 - * - * Date: Sun Dec 11 15:08:42 2011 EST - * Requires: jQuery v1.3+ - * - * Copyright 2011, Karl Swedberg - * Dual licensed under the MIT and GPL licenses (just like jQuery): - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * - * https://github.com/kswedberg/jquery-expander/blob/a3393d68e28cde673a53cabba2cd49dc8d980f7f/jquery.expander.js - * - * -*/ - -(function($) { - $.expander = { - version: '1.4', - defaults: { - // the number of characters at which the contents will be sliced into two parts. - slicePoint: 100, - - // whether to keep the last word of the summary whole (true) or let it slice in the middle of a word (false) - preserveWords: true, - - // a threshold of sorts for whether to initially hide/collapse part of the element's contents. - // If after slicing the contents in two there are fewer words in the second part than - // the value set by widow, we won't bother hiding/collapsing anything. - widow: 4, - - // text displayed in a link instead of the hidden part of the element. - // clicking this will expand/show the hidden/collapsed text - expandText: 'read more', - expandPrefix: '… ', - - expandAfterSummary: false, - - // class names for summary element and detail element - summaryClass: 'summary', - detailClass: 'details', - - // class names for <span> around "read-more" link and "read-less" link - moreClass: 'read-more', - lessClass: 'read-less', - - // number of milliseconds after text has been expanded at which to collapse the text again. - // when 0, no auto-collapsing - collapseTimer: 0, - - // effects for expanding and collapsing - expandEffect: 'fadeIn', - expandSpeed: 250, - collapseEffect: 'fadeOut', - collapseSpeed: 200, - - // allow the user to re-collapse the expanded text. - userCollapse: true, - - // text to use for the link to re-collapse the text - userCollapseText: 'read less', - userCollapsePrefix: ' ', - - - // all callback functions have the this keyword mapped to the element in the jQuery set when .expander() is called - - onSlice: null, // function() {} - beforeExpand: null, // function() {}, - afterExpand: null, // function() {}, - onCollapse: null // function(byUser) {} - } - }; - - $.fn.expander = function(options) { - var meth = 'init'; - - if (typeof options == 'string') { - meth = options; - options = {}; - } - - var opts = $.extend({}, $.expander.defaults, options), - rSelfClose = /^<(?:area|br|col|embed|hr|img|input|link|meta|param).*>$/i, - rAmpWordEnd = /(&(?:[^;]+;)?|\w+)$/, - rOpenCloseTag = /<\/?(\w+)[^>]*>/g, - rOpenTag = /<(\w+)[^>]*>/g, - rCloseTag = /<\/(\w+)>/g, - rLastCloseTag = /(<\/[^>]+>)\s*$/, - rTagPlus = /^<[^>]+>.?/, - delayedCollapse; - - var methods = { - init: function() { - this.each(function() { - var i, l, tmp, summTagLess, summOpens, summCloses, lastCloseTag, detailText, - $thisDetails, $readMore, - openTagsForDetails = [], - closeTagsForsummaryText = [], - defined = {}, - thisEl = this, - $this = $(this), - $summEl = $([]), - o = $.meta ? $.extend({}, opts, $this.data()) : opts, - hasDetails = !!$this.find('.' + o.detailClass).length, - hasBlocks = !!$this.find('*').filter(function() { - var display = $(this).css('display'); - return (/^block|table|list/).test(display); - }).length, - el = hasBlocks ? 'div' : 'span', - detailSelector = el + '.' + o.detailClass, - moreSelector = 'span.' + o.moreClass, - expandSpeed = o.expandSpeed || 0, - allHtml = $.trim( $this.html() ), - allText = $.trim( $this.text() ), - summaryText = allHtml.slice(0, o.slicePoint); - - // bail out if we've already set up the expander on this element - if ( $.data(this, 'expander') ) { - return; - } - $.data(this, 'expander', true); - - // determine which callback functions are defined - $.each(['onSlice','beforeExpand', 'afterExpand', 'onCollapse'], function(index, val) { - defined[val] = $.isFunction(o[val]); - }); - - // back up if we're in the middle of a tag or word - summaryText = backup(summaryText); - - // summary text sans tags length - summTagless = summaryText.replace(rOpenCloseTag, '').length; - - // add more characters to the summary, one for each character in the tags - while (summTagless < o.slicePoint) { - newChar = allHtml.charAt(summaryText.length); - if (newChar == '<') { - newChar = allHtml.slice(summaryText.length).match(rTagPlus)[0]; - } - summaryText += newChar; - summTagless++; - } - - summaryText = backup(summaryText, o.preserveWords); - - // separate open tags from close tags and clean up the lists - summOpens = summaryText.match(rOpenTag) || []; - summCloses = summaryText.match(rCloseTag) || []; - - // filter out self-closing tags - tmp = []; - $.each(summOpens, function(index, val) { - if ( !rSelfClose.test(val) ) { - tmp.push(val); - } - }); - summOpens = tmp; - - // strip close tags to just the tag name - l = summCloses.length; - for (i = 0; i < l; i++) { - summCloses[i] = summCloses[i].replace(rCloseTag, '$1'); - } - - // tags that start in summary and end in detail need: - // a). close tag at end of summary - // b). open tag at beginning of detail - $.each(summOpens, function(index, val) { - var thisTagName = val.replace(rOpenTag, '$1'); - var closePosition = $.inArray(thisTagName, summCloses); - if (closePosition === -1) { - openTagsForDetails.push(val); - closeTagsForsummaryText.push('</' + thisTagName + '>'); - - } else { - summCloses.splice(closePosition, 1); - } - }); - - // reverse the order of the close tags for the summary so they line up right - closeTagsForsummaryText.reverse(); - - // create necessary summary and detail elements if they don't already exist - if ( !hasDetails ) { - - // end script if there is no detail text or if detail has fewer words than widow option - detailText = allHtml.slice(summaryText.length); - - if ( detailText === '' || detailText.split(/\s+/).length < o.widow ) { - return; - } - - // otherwise, continue... - lastCloseTag = closeTagsForsummaryText.pop() || ''; - summaryText += closeTagsForsummaryText.join(''); - detailText = openTagsForDetails.join('') + detailText; - - } else { - // assume that even if there are details, we still need readMore/readLess/summary elements - // (we already bailed out earlier when readMore el was found) - // but we need to create els differently - - // remove the detail from the rest of the content - detailText = $this.find(detailSelector).remove().html(); - - // The summary is what's left - summaryText = $this.html(); - - // allHtml is the summary and detail combined (this is needed when content has block-level elements) - allHtml = summaryText + detailText; - - lastCloseTag = ''; - } - o.moreLabel = $this.find(moreSelector).length ? '' : buildMoreLabel(o); - - if (hasBlocks) { - detailText = allHtml; - } - summaryText += lastCloseTag; - - // onSlice callback - o.summary = summaryText; - o.details = detailText; - o.lastCloseTag = lastCloseTag; - - if (defined.onSlice) { - // user can choose to return a modified options object - // one last chance for user to change the options. sneaky, huh? - // but could be tricky so use at your own risk. - tmp = o.onSlice.call(thisEl, o); - - // so, if the returned value from the onSlice function is an object with a details property, we'll use that! - o = tmp && tmp.details ? tmp : o; - } - - // build the html with summary and detail and use it to replace old contents - var html = buildHTML(o, hasBlocks); - - $this.html( html ); - - // set up details and summary for expanding/collapsing - $thisDetails = $this.find(detailSelector); - $readMore = $this.find(moreSelector); - $thisDetails.hide(); - $readMore.find('a').unbind('click.expander').bind('click.expander', expand); - - $summEl = $this.find('div.' + o.summaryClass); - - if ( o.userCollapse && !$this.find('span.' + o.lessClass).length ) { - $this - .find(detailSelector) - .append('<span class="' + o.lessClass + '">' + o.userCollapsePrefix + '<a href="#">' + o.userCollapseText + '</a></span>'); - } - - $this - .find('span.' + o.lessClass + ' a') - .unbind('click.expander') - .bind('click.expander', function(event) { - event.preventDefault(); - clearTimeout(delayedCollapse); - var $detailsCollapsed = $(this).closest(detailSelector); - reCollapse(o, $detailsCollapsed); - if (defined.onCollapse) { - o.onCollapse.call(thisEl, true); - } - }); - - function expand(event) { - event.preventDefault(); - $readMore.hide(); - $summEl.hide(); - if (defined.beforeExpand) { - o.beforeExpand.call(thisEl); - } - - $thisDetails.stop(false, true)[o.expandEffect](expandSpeed, function() { - $thisDetails.css({zoom: ''}); - if (defined.afterExpand) {o.afterExpand.call(thisEl);} - delayCollapse(o, $thisDetails, thisEl); - }); - } - - }); // this.each - }, - destroy: function() { - if ( !this.data('expander') ) { - return; - } - this.removeData('expander'); - this.each(function() { - var $this = $(this), - o = $.meta ? $.extend({}, opts, $this.data()) : opts, - details = $this.find('.' + o.detailClass).contents(); - - $this.find('.' + o.moreClass).remove(); - $this.find('.' + o.summaryClass).remove(); - $this.find('.' + o.detailClass).after(details).remove(); - $this.find('.' + o.lessClass).remove(); - - }); - } - }; - - // run the methods (almost always "init") - if ( methods[meth] ) { - methods[ meth ].call(this); - } - - // utility functions - function buildHTML(o, blocks) { - var el = 'span', - summary = o.summary; - if ( blocks ) { - el = 'div'; - // if summary ends with a close tag, tuck the moreLabel inside it - if ( rLastCloseTag.test(summary) && !o.expandAfterSummary) { - summary = summary.replace(rLastCloseTag, o.moreLabel + '$1'); - } else { - // otherwise (e.g. if ends with self-closing tag) just add moreLabel after summary - // fixes #19 - summary += o.moreLabel; - } - - // and wrap it in a div - summary = '<div class="' + o.summaryClass + '">' + summary + '</div>'; - } else { - summary += o.moreLabel; - } - - return [ - summary, - '<', - el + ' class="' + o.detailClass + '"', - '>', - o.details, - '</' + el + '>' - ].join(''); - } - - function buildMoreLabel(o) { - var ret = '<span class="' + o.moreClass + '">' + o.expandPrefix; - ret += '<a href="#">' + o.expandText + '</a></span>'; - return ret; - } - - function backup(txt, preserveWords) { - if ( txt.lastIndexOf('<') > txt.lastIndexOf('>') ) { - txt = txt.slice( 0, txt.lastIndexOf('<') ); - } - if (preserveWords) { - txt = txt.replace(rAmpWordEnd,''); - } - return txt; - } - - function reCollapse(o, el) { - el.stop(true, true)[o.collapseEffect](o.collapseSpeed, function() { - var prevMore = el.prev('span.' + o.moreClass).show(); - if (!prevMore.length) { - el.parent().children('div.' + o.summaryClass).show() - .find('span.' + o.moreClass).show(); - } - }); - } - - function delayCollapse(option, $collapseEl, thisEl) { - if (option.collapseTimer) { - delayedCollapse = setTimeout(function() { - reCollapse(option, $collapseEl); - if ( $.isFunction(option.onCollapse) ) { - option.onCollapse.call(thisEl, false); - } - }, option.collapseTimer); - } - } - - return this; - }; - - // plugin defaults - $.fn.expander.defaults = $.expander.defaults; -})(jQuery); diff --git a/hyperkitty/static/js/libs/protovis-d3.1.js b/hyperkitty/static/js/libs/protovis-d3.1.js deleted file mode 100644 index af56eac..0000000 --- a/hyperkitty/static/js/libs/protovis-d3.1.js +++ /dev/null @@ -1,7725 +0,0 @@ -/** - * @class The built-in Array class. - * @name Array - */ - -if (!Array.prototype.map) { - /** - * Creates a new array with the results of calling a provided function on - * every element in this array. Implemented in Javascript 1.6. - * - * @see <a - * href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/Map">map</a> - * documentation. - * @param {function} f function that produces an element of the new Array from - * an element of the current one. - * @param [o] object to use as <tt>this</tt> when executing <tt>f</tt>. - */ - Array.prototype.map = function(f, o) { - var n = this.length; - var result = new Array(n); - for (var i = 0; i < n; i++) { - if (i in this) { - result[i] = f.call(o, this[i], i, this); - } - } - return result; - }; -} - -if (!Array.prototype.filter) { - /** - * Creates a new array with all elements that pass the test implemented by the - * provided function. Implemented in Javascript 1.6. - * - * @see <a - * href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/filter">filter</a> - * documentation. - * @param {function} f function to test each element of the array. - * @param [o] object to use as <tt>this</tt> when executing <tt>f</tt>. - */ - Array.prototype.filter = function(f, o) { - var n = this.length; - var result = new Array(); - for (var i = 0; i < n; i++) { - if (i in this) { - var v = this[i]; - if (f.call(o, v, i, this)) result.push(v); - } - } - return result; - }; -} - -if (!Array.prototype.forEach) { - /** - * Executes a provided function once per array element. Implemented in - * Javascript 1.6. - * - * @see <a - * href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/ForEach">forEach</a> - * documentation. - * @param {function} f function to execute for each element. - * @param [o] object to use as <tt>this</tt> when executing <tt>f</tt>. - */ - Array.prototype.forEach = function(f, o) { - var n = this.length >>> 0; - for (var i = 0; i < n; i++) { - if (i in this) f.call(o, this[i], i, this); - } - }; -} - -if (!Array.prototype.reduce) { - /** - * Apply a function against an accumulator and each value of the array (from - * left-to-right) as to reduce it to a single value. Implemented in Javascript - * 1.8. - * - * @see <a - * href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/Reduce">reduce</a> - * documentation. - * @param {function} f function to execute on each value in the array. - * @param [v] object to use as the first argument to the first call of - * <tt>t</tt>. - */ - Array.prototype.reduce = function(f, v) { - var len = this.length; - if (!len && (arguments.length == 1)) { - throw new Error("reduce: empty array, no initial value"); - } - - var i = 0; - if (arguments.length < 2) { - while (true) { - if (i in this) { - v = this[i++]; - break; - } - if (++i >= len) { - throw new Error("reduce: no values, no initial value"); - } - } - } - - for (; i < len; i++) { - if (i in this) { - v = f(v, this[i], i, this); - } - } - return v; - }; -} -/** - * @class The built-in Date class. - * @name Date - */ - -Date.__parse__ = Date.parse; - -/** - * Parses a date from a string, optionally using the specified formatting. If - * only a single argument is specified (i.e., <tt>format</tt> is not specified), - * this method invokes the native implementation to guarantee - * backwards-compatibility. - * - * <p>The format string is in the same format expected by the <tt>strptime</tt> - * function in C. The following conversion specifications are supported:<ul> - * - * <li>%b - abbreviated month names.</li> - * <li>%B - full month names.</li> - * <li>%h - same as %b.</li> - * <li>%d - day of month [1,31].</li> - * <li>%e - same as %d.</li> - * <li>%H - hour (24-hour clock) [0,23].</li> - * <li>%m - month number [1,12].</li> - * <li>%M - minute [0,59].</li> - * <li>%S - second [0,61].</li> - * <li>%y - year with century [0,99].</li> - * <li>%Y - year including century.</li> - * <li>%% - %.</li> - * - * </ul>The following conversion specifications are <i>unsupported</i> (for now):<ul> - * - * <li>%a - day of week, either abbreviated or full name.</li> - * <li>%A - same as %a.</li> - * <li>%c - locale's appropriate date and time.</li> - * <li>%C - century number.</li> - * <li>%D - same as %m/%d/%y.</li> - * <li>%I - hour (12-hour clock) [1,12].</li> - * <li>%j - day number [1,366].</li> - * <li>%n - any white space.</li> - * <li>%p - locale's equivalent of a.m. or p.m.</li> - * <li>%r - same as %I:%M:%S %p.</li> - * <li>%R - same as %H:%M.</li> - * <li>%t - same as %n.</li> - * <li>%T - same as %H:%M:%S.</li> - * <li>%U - week number [0,53].</li> - * <li>%w - weekday [0,6].</li> - * <li>%W - week number [0,53].</li> - * <li>%x - locale's equivalent to %m/%d/%y.</li> - * <li>%X - locale's equivalent to %I:%M:%S %p.</li> - * - * </ul> - * - * @see <a - * href="http://www.opengroup.org/onlinepubs/007908799/xsh/strptime.html">strptime</a> - * documentation. - * @param {string} s the string to parse as a date. - * @param {string} [format] an optional format string. - * @returns {Date} the parsed date. - */ -Date.parse = function(s, format) { - if (arguments.length == 1) { - return Date.__parse__(s); - } - - var year = 1970, month = 0, date = 1, hour = 0, minute = 0, second = 0; - var fields = [function() {}]; - format = format.replace(/[\\\^\$\*\+\?\[\]\(\)\.\{\}]/g, "\\$&"); - format = format.replace(/%[a-zA-Z0-9]/g, function(s) { - switch (s) { - // TODO %a: day of week, either abbreviated or full name - // TODO %A: same as %a - case '%b': { - fields.push(function(x) { month = { - Jan: 0, Feb: 1, Mar: 2, Apr: 3, May: 4, Jun: 5, Jul: 6, Aug: 7, - Sep: 8, Oct: 9, Nov: 10, Dec: 11 - }[x]; }); - return "([A-Za-z]+)"; - } - case '%h': - case '%B': { - fields.push(function(x) { month = { - January: 0, February: 1, March: 2, April: 3, May: 4, June: 5, - July: 6, August: 7, September: 8, October: 9, November: 10, - December: 11 - }[x]; }); - return "([A-Za-z]+)"; - } - // TODO %c: locale's appropriate date and time - // TODO %C: century number[0,99] - case '%e': - case '%d': { - fields.push(function(x) { date = x; }); - return "([0-9]+)"; - } - // TODO %D: same as %m/%d/%y - case '%H': { - fields.push(function(x) { hour = x; }); - return "([0-9]+)"; - } - // TODO %I: hour (12-hour clock) [1,12] - // TODO %j: day number [1,366] - case '%m': { - fields.push(function(x) { month = x - 1; }); - return "([0-9]+)"; - } - case '%M': { - fields.push(function(x) { minute = x; }); - return "([0-9]+)"; - } - // TODO %n: any white space - // TODO %p: locale's equivalent of a.m. or p.m. - // TODO %r: %I:%M:%S %p - // TODO %R: %H:%M - case '%S': { - fields.push(function(x) { second = x; }); - return "([0-9]+)"; - } - // TODO %t: any white space - // TODO %T: %H:%M:%S - // TODO %U: week number [00,53] - // TODO %w: weekday [0,6] - // TODO %W: week number [00, 53] - // TODO %x: locale date (%m/%d/%y) - // TODO %X: locale time (%I:%M:%S %p) - case '%y': { - fields.push(function(x) { - x = Number(x); - year = x + (((0 <= x) && (x < 69)) ? 2000 - : (((x >= 69) && (x < 100) ? 1900 : 0))); - }); - return "([0-9]+)"; - } - case '%Y': { - fields.push(function(x) { year = x; }); - return "([0-9]+)"; - } - case '%%': { - fields.push(function() {}); - return "%"; - } - } - return s; - }); - - var match = s.match(format); - if (match) match.forEach(function(m, i) { fields[i](m); }); - return new Date(year, month, date, hour, minute, second); -}; - -if (Date.prototype.toLocaleFormat) { - Date.prototype.format = Date.prototype.toLocaleFormat; -} else { - -/** - * Converts a date to a string using the specified formatting. If the - * <tt>Date</tt> object already supports the <tt>toLocaleFormat</tt> method, as - * in Firefox, this is simply an alias to the built-in method. - * - * <p>The format string is in the same format expected by the <tt>strftime</tt> - * function in C. The following conversion specifications are supported:<ul> - * - * <li>%a - abbreviated weekday name.</li> - * <li>%A - full weekday name.</li> - * <li>%b - abbreviated month names.</li> - * <li>%B - full month names.</li> - * <li>%c - locale's appropriate date and time.</li> - * <li>%C - century number.</li> - * <li>%d - day of month [01,31] (zero padded).</li> - * <li>%D - same as %m/%d/%y.</li> - * <li>%e - day of month [ 1,31] (space padded).</li> - * <li>%h - same as %b.</li> - * <li>%H - hour (24-hour clock) [00,23] (zero padded).</li> - * <li>%I - hour (12-hour clock) [01,12] (zero padded).</li> - * <li>%m - month number [01,12] (zero padded).</li> - * <li>%M - minute [0,59] (zero padded).</li> - * <li>%n - newline character.</li> - * <li>%p - locale's equivalent of a.m. or p.m.</li> - * <li>%r - same as %I:%M:%S %p.</li> - * <li>%R - same as %H:%M.</li> - * <li>%S - second [00,61] (zero padded).</li> - * <li>%t - tab character.</li> - * <li>%T - same as %H:%M:%S.</li> - * <li>%x - same as %m/%d/%y.</li> - * <li>%X - same as %I:%M:%S %p.</li> - * <li>%y - year with century [00,99] (zero padded).</li> - * <li>%Y - year including century.</li> - * <li>%% - %.</li> - * - * </ul>The following conversion specifications are <i>unsupported</i> (for now):<ul> - * - * <li>%j - day number [1,366].</li> - * <li>%u - weekday number [1,7].</li> - * <li>%U - week number [00,53].</li> - * <li>%V - week number [01,53].</li> - * <li>%w - weekday number [0,6].</li> - * <li>%W - week number [00,53].</li> - * <li>%Z - timezone name or abbreviation.</li> - * - * </ul> - * - * @see <a - * href="http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Date/toLocaleFormat">Date.toLocaleFormat</a> - * documentation. - * @see <a - * href="http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html">strftime</a> - * documentation. - * @param {string} format a format string. - * @returns {string} the formatted date. - */ -Date.prototype.format = function(format) { - function pad(n, p) { return (n < 10) ? (p || "0") + n : n; } - var d = this; - return format.replace(/%[a-zA-Z0-9]/g, function(s) { - switch (s) { - case '%a': return [ - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - ][d.getDay()]; - case '%A': return [ - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", - "Saturday" - ][d.getDay()]; - case '%h': - case '%b': return [ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", - "Oct", "Nov", "Dec" - ][d.getMonth()]; - case '%B': return [ - "January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December" - ][d.getMonth()]; - case '%c': return d.toLocaleString(); - case '%C': return pad(Math.floor(d.getFullYear() / 100) % 100); - case '%d': return pad(d.getDate()); - case '%x': - case '%D': return pad(d.getMonth() + 1) - + "/" + pad(d.getDate()) - + "/" + pad(d.getFullYear() % 100); - case '%e': return pad(d.getDate(), " "); - case '%H': return pad(d.getHours()); - case '%I': { - var h = d.getHours() % 12; - return h ? pad(h) : 12; - } - // TODO %j: day of year as a decimal number [001,366] - case '%m': return pad(d.getMonth() + 1); - case '%M': return pad(d.getMinutes()); - case '%n': return "\n"; - case '%p': return d.getHours() < 12 ? "AM" : "PM"; - case '%T': - case '%X': - case '%r': { - var h = d.getHours() % 12; - return (h ? pad(h) : 12) - + ":" + pad(d.getMinutes()) - + ":" + pad(d.getSeconds()) - + " " + (d.getHours() < 12 ? "AM" : "PM"); - } - case '%R': return pad(d.getHours()) + ":" + pad(d.getMinutes()); - case '%S': return pad(d.getSeconds()); - case '%t': return "\t"; - case '%u': { - var w = d.getDay(); - return w ? w : 1; - } - // TODO %U: week number (sunday first day) [00,53] - // TODO %V: week number (monday first day) [01,53] ... with weirdness - case '%w': return d.getDay(); - // TODO %W: week number (monday first day) [00,53] ... with weirdness - case '%y': return pad(d.getFullYear() % 100); - case '%Y': return d.getFullYear(); - // TODO %Z: timezone name or abbreviation - case '%%': return "%"; - } - return s; - }); - }; -} -var pv = function() {/** - * The top-level Protovis namespace. All public methods and fields should be - * registered on this object. Note that core Protovis source is surrounded by an - * anonymous function, so any other declared globals will not be visible outside - * of core methods. This also allows multiple versions of Protovis to coexist, - * since each version will see their own <tt>pv</tt> namespace. - * - * @namespace The top-level Protovis namespace, <tt>pv</tt>. - */ -var pv = {}; - -/** - * @private Returns a prototype object suitable for extending the given class - * <tt>f</tt>. Rather than constructing a new instance of <tt>f</tt> to serve as - * the prototype (which unnecessarily runs the constructor on the created - * prototype object, potentially polluting it), an anonymous function is - * generated internally that shares the same prototype: - * - * <pre>function g() {} - * g.prototype = f.prototype; - * return new g();</pre> - * - * For more details, see Douglas Crockford's essay on prototypal inheritance. - * - * @param {function} f a constructor. - * @returns a suitable prototype object. - * @see Douglas Crockford's essay on <a - * href="http://javascript.crockford.com/prototypal.html">prototypal - * inheritance</a>. - */ -pv.extend = function(f) { - function g() {} - g.prototype = f.prototype || f; - return new g(); -}; - -try { - eval("pv.parse = function(x) x;"); // native support -} catch (e) { - -/** - * @private Parses a Protovis specification, which may use JavaScript 1.8 - * function expresses, replacing those function expressions with proper - * functions such that the code can be run by a JavaScript 1.6 interpreter. This - * hack only supports function expressions (using clumsy regular expressions, no - * less), and not other JavaScript 1.8 features such as let expressions. - * - * @param {string} s a Protovis specification (i.e., a string of JavaScript 1.8 - * source code). - * @returns {string} a conformant JavaScript 1.6 source code. - */ - pv.parse = function(js) { // hacky regex support - var re = new RegExp("function(\\s+\\w+)?\\([^)]*\\)\\s*", "mg"), m, d, i = 0, s = ""; - while (m = re.exec(js)) { - var j = m.index + m[0].length; - if (js.charAt(j--) != '{') { - s += js.substring(i, j) + "{return "; - i = j; - for (var p = 0; p >= 0 && j < js.length; j++) { - var c = js.charAt(j); - switch (c) { - case '"': case '\'': { - while (++j < js.length && (d = js.charAt(j)) != c) { - if (d == '\\') j++; - } - break; - } - case '[': case '(': p++; break; - case ']': case ')': p--; break; - case ';': - case ',': if (p == 0) p--; break; - } - } - s += pv.parse(js.substring(i, --j)) + ";}"; - i = j; - } - re.lastIndex = j; - } - s += js.substring(i); - return s; - }; -} - -/** - * Returns the passed-in argument, <tt>x</tt>; the identity function. This method - * is provided for convenience since it is used as the default behavior for a - * number of property functions. - * - * @param x a value. - * @returns the value <tt>x</tt>. - */ -pv.identity = function(x) { return x; }; - -/** - * Returns <tt>this.index</tt>. This method is provided for convenience for use - * with scales. For example, to color bars by their index, say: - * - * <pre>.fillStyle(pv.Colors.category10().by(pv.index))</pre> - * - * This method is equivalent to <tt>function() this.index</tt>, but more - * succinct. Note that the <tt>index</tt> property is also supported for - * accessor functions with {@link pv.max}, {@link pv.min} and other array - * utility methods. - * - * @see pv.Scale - * @see pv.Mark#index - */ -pv.index = function() { return this.index; }; - -/** - * Returns <tt>this.childIndex</tt>. This method is provided for convenience for - * use with scales. For example, to color bars by their child index, say: - * - * <pre>.fillStyle(pv.Colors.category10().by(pv.child))</pre> - * - * This method is equivalent to <tt>function() this.childIndex</tt>, but more - * succinct. - * - * @see pv.Scale - * @see pv.Mark#childIndex - */ -pv.child = function() { return this.childIndex; }; - -/** - * Returns <tt>this.parent.index</tt>. This method is provided for convenience - * for use with scales. This method is provided for convenience for use with - * scales. For example, to color bars by their parent index, say: - * - * <pre>.fillStyle(pv.Colors.category10().by(pv.parent))</pre> - * - * Tthis method is equivalent to <tt>function() this.parent.index</tt>, but more - * succinct. - * - * @see pv.Scale - * @see pv.Mark#index - */ -pv.parent = function() { return this.parent.index; }; - -/** - * Returns an array of numbers, starting at <tt>start</tt>, incrementing by - * <tt>step</tt>, until <tt>stop</tt> is reached. The stop value is exclusive. If - * only a single argument is specified, this value is interpeted as the - * <i>stop</i> value, with the <i>start</i> value as zero. If only two arguments - * are specified, the step value is implied to be one. - * - * <p>The method is modeled after the built-in <tt>range</tt> method from - * Python. See the Python documentation for more details. - * - * @see <a href="http://docs.python.org/library/functions.html#range">Python range</a> - * @param {number} [start] the start value. - * @param {number} stop the stop value. - * @param {number} [step] the step value. - * @returns {number[]} an array of numbers. - */ -pv.range = function(start, stop, step) { - if (arguments.length == 1) { - stop = start; - start = 0; - } - if (step == undefined) step = 1; - else if (!step) throw new Error("step must be non-zero"); - var array = [], i = 0, j; - if (step < 0) { - while ((j = start + step * i++) > stop) { - array.push(j); - } - } else { - while ((j = start + step * i++) < stop) { - array.push(j); - } - } - return array; -}; - -/** - * Returns a random number in the range [<tt>min</tt>, <tt>max</tt>) that is a - * multiple of <tt>step</tt>. More specifically, the returned number is of the - * form <tt>min</tt> + <i>n</i> * <tt>step</tt>, where <i>n</i> is a nonnegative - * integer. If <tt>step</tt> is not specified, it defaults to 1, returning a - * random integer if <tt>min</tt> is also an integer. - * - * @param min {number} minimum value. - * @param [max] {number} maximum value. - * @param [step] {numbeR} step value. - */ -pv.random = function(min, max, step) { - if (arguments.length == 1) { - max = min; - min = 0; - } - if (step == undefined) { - step = 1; - } - return step - ? (Math.floor(Math.random() * (max - min) / step) * step + min) - : (Math.random() * (max - min) + min); -}; - -/** - * Concatenates the specified array with itself <i>n</i> times. For example, - * <tt>pv.repeat([1, 2])</tt> returns [1, 2, 1, 2]. - * - * @param {array} a an array. - * @param {number} [n] the number of times to repeat; defaults to two. - * @returns {array} an array that repeats the specified array. - */ -pv.repeat = function(array, n) { - if (arguments.length == 1) n = 2; - return pv.blend(pv.range(n).map(function() { return array; })); -}; - -/** - * Given two arrays <tt>a</tt> and <tt>b</tt>, <style - * type="text/css">sub{line-height:0}</style> returns an array of all possible - * pairs of elements [a<sub>i</sub>, b<sub>j</sub>]. The outer loop is on array - * <i>a</i>, while the inner loop is on <i>b</i>, such that the order of - * returned elements is [a<sub>0</sub>, b<sub>0</sub>], [a<sub>0</sub>, - * b<sub>1</sub>], ... [a<sub>0</sub>, b<sub>m</sub>], [a<sub>1</sub>, - * b<sub>0</sub>], [a<sub>1</sub>, b<sub>1</sub>], ... [a<sub>1</sub>, - * b<sub>m</sub>], ... [a<sub>n</sub>, b<sub>m</sub>]. If either array is empty, - * an empty array is returned. - * - * @param {array} a an array. - * @param {array} b an array. - * @returns {array} an array of pairs of elements in <tt>a</tt> and <tt>b</tt>. - */ -pv.cross = function(a, b) { - var array = []; - for (var i = 0, n = a.length, m = b.length; i < n; i++) { - for (var j = 0, x = a[i]; j < m; j++) { - array.push([x, b[j]]); - } - } - return array; -}; - -/** - * Given the specified array of arrays, concatenates the arrays into a single - * array. If the individual arrays are explicitly known, an alternative to blend - * is to use JavaScript's <tt>concat</tt> method directly. These two equivalent - * expressions:<ul> - * - * <li><tt>pv.blend([[1, 2, 3], ["a", "b", "c"]])</tt> - * <li><tt>[1, 2, 3].concat(["a", "b", "c"])</tt> - * - * </ul>return [1, 2, 3, "a", "b", "c"]. - * - * @param {array[]} arrays an array of arrays. - * @returns {array} an array containing all the elements of each array in - * <tt>arrays</tt>. - */ -pv.blend = function(arrays) { - return Array.prototype.concat.apply([], arrays); -}; - -/** - * Given the specified array of arrays, <style - * type="text/css">sub{line-height:0}</style> transposes each element - * array<sub>ij</sub> with array<sub>ji</sub>. If the array has dimensions - * <i>n</i>×<i>m</i>, it will have dimensions <i>m</i>×<i>n</i> - * after this method returns. This method transposes the elements of the array - * in place, mutating the array, and returning a reference to the array. - * - * @param {array[]} arrays an array of arrays. - * @returns {array[]} the passed-in array, after transposing the elements. - */ -pv.transpose = function(arrays) { - var n = arrays.length, m = pv.max(arrays, function(d) { return d.length; }); - - if (m > n) { - arrays.length = m; - for (var i = n; i < m; i++) { - arrays[i] = new Array(n); - } - for (var i = 0; i < n; i++) { - for (var j = i + 1; j < m; j++) { - var t = arrays[i][j]; - arrays[i][j] = arrays[j][i]; - arrays[j][i] = t; - } - } - } else { - for (var i = 0; i < m; i++) { - arrays[i].length = n; - } - for (var i = 0; i < n; i++) { - for (var j = 0; j < i; j++) { - var t = arrays[i][j]; - arrays[i][j] = arrays[j][i]; - arrays[j][i] = t; - } - } - } - - arrays.length = m; - for (var i = 0; i < m; i++) { - arrays[i].length = n; - } - - return arrays; -}; - -/** - * Returns all of the property names (keys) of the specified object (a map). The - * order of the returned array is not defined. - * - * @param map an object. - * @returns {string[]} an array of strings corresponding to the keys. - * @see #entries - */ -pv.keys = function(map) { - var array = []; - for (var key in map) { - array.push(key); - } - return array; -}; - -/** - * Returns all of the entries (key-value pairs) of the specified object (a - * map). The order of the returned array is not defined. Each key-value pair is - * represented as an object with <tt>key</tt> and <tt>value</tt> attributes, - * e.g., <tt>{key: "foo", value: 42}</tt>. - * - * @param map an object. - * @returns {array} an array of key-value pairs corresponding to the keys. - */ -pv.entries = function(map) { - var array = []; - for (var key in map) { - array.push({ key: key, value: map[key] }); - } - return array; -}; - -/** - * Returns all of the values (attribute values) of the specified object (a - * map). The order of the returned array is not defined. - * - * @param map an object. - * @returns {array} an array of objects corresponding to the values. - * @see #entries - */ -pv.values = function(map) { - var array = []; - for (var key in map) { - array.push(map[key]); - } - return array; -}; - -/** - * @private A private variant of Array.prototype.map that supports the index - * property. - */ -function map(array, f) { - var o = {}; - return f - ? array.map(function(d, i) { o.index = i; return f.call(o, d); }) - : array.slice(); -}; - -/** - * Returns a normalized copy of the specified array, such that the sum of the - * returned elements sum to one. If the specified array is not an array of - * numbers, an optional accessor function <tt>f</tt> can be specified to map the - * elements to numbers. For example, if <tt>array</tt> is an array of objects, - * and each object has a numeric property "foo", the expression - * - * <pre>pv.normalize(array, function(d) d.foo)</pre> - * - * returns a normalized array on the "foo" property. If an accessor function is - * not specified, the identity function is used. Accessor functions can refer to - * <tt>this.index</tt>. - * - * @param {array} array an array of objects, or numbers. - * @param {function} [f] an optional accessor function. - * @returns {number[]} an array of numbers that sums to one. - */ -pv.normalize = function(array, f) { - var norm = map(array, f), sum = pv.sum(norm); - for (var i = 0; i < norm.length; i++) norm[i] /= sum; - return norm; -}; - -/** - * Returns the sum of the specified array. If the specified array is not an - * array of numbers, an optional accessor function <tt>f</tt> can be specified - * to map the elements to numbers. See {@link #normalize} for an example. - * Accessor functions can refer to <tt>this.index</tt>. - * - * @param {array} array an array of objects, or numbers. - * @param {function} [f] an optional accessor function. - * @returns {number} the sum of the specified array. - */ -pv.sum = function(array, f) { - var o = {}; - return array.reduce(f - ? function(p, d, i) { o.index = i; return p + f.call(o, d); } - : function(p, d) { return p + d; }, 0); -}; - -/** - * Returns the maximum value of the specified array. If the specified array is - * not an array of numbers, an optional accessor function <tt>f</tt> can be - * specified to map the elements to numbers. See {@link #normalize} for an - * example. Accessor functions can refer to <tt>this.index</tt>. - * - * @param {array} array an array of objects, or numbers. - * @param {function} [f] an optional accessor function. - * @returns {number} the maximum value of the specified array. - */ -pv.max = function(array, f) { - if (f == pv.index) return array.length - 1; - return Math.max.apply(null, f ? map(array, f) : array); -}; - -/** - * Returns the index of the maximum value of the specified array. If the - * specified array is not an array of numbers, an optional accessor function - * <tt>f</tt> can be specified to map the elements to numbers. See - * {@link #normalize} for an example. Accessor functions can refer to - * <tt>this.index</tt>. - * - * @param {array} array an array of objects, or numbers. - * @param {function} [f] an optional accessor function. - * @returns {number} the index of the maximum value of the specified array. - */ -pv.max.index = function(array, f) { - if (f == pv.index) return array.length - 1; - if (!f) f = pv.identity; - var maxi = -1, maxx = -Infinity, o = {}; - for (var i = 0; i < array.length; i++) { - o.index = i; - var x = f.call(o, array[i]); - if (x > maxx) { - maxx = x; - maxi = i; - } - } - return maxi; -} - -/** - * Returns the minimum value of the specified array of numbers. If the specified - * array is not an array of numbers, an optional accessor function <tt>f</tt> - * can be specified to map the elements to numbers. See {@link #normalize} for - * an example. Accessor functions can refer to <tt>this.index</tt>. - * - * @param {array} array an array of objects, or numbers. - * @param {function} [f] an optional accessor function. - * @returns {number} the minimum value of the specified array. - */ -pv.min = function(array, f) { - if (f == pv.index) return 0; - return Math.min.apply(null, f ? map(array, f) : array); -}; - -/** - * Returns the index of the minimum value of the specified array. If the - * specified array is not an array of numbers, an optional accessor function - * <tt>f</tt> can be specified to map the elements to numbers. See - * {@link #normalize} for an example. Accessor functions can refer to - * <tt>this.index</tt>. - * - * @param {array} array an array of objects, or numbers. - * @param {function} [f] an optional accessor function. - * @returns {number} the index of the minimum value of the specified array. - */ -pv.min.index = function(array, f) { - if (f == pv.index) return 0; - if (!f) f = pv.identity; - var mini = -1, minx = Infinity, o = {}; - for (var i = 0; i < array.length; i++) { - o.index = i; - var x = f.call(o, array[i]); - if (x < minx) { - minx = x; - mini = i; - } - } - return mini; -} - -/** - * Returns the arithmetic mean, or average, of the specified array. If the - * specified array is not an array of numbers, an optional accessor function - * <tt>f</tt> can be specified to map the elements to numbers. See - * {@link #normalize} for an example. Accessor functions can refer to - * <tt>this.index</tt>. - * - * @param {array} array an array of objects, or numbers. - * @param {function} [f] an optional accessor function. - * @returns {number} the mean of the specified array. - */ -pv.mean = function(array, f) { - return pv.sum(array, f) / array.length; -}; - -/** - * Returns the median of the specified array. If the specified array is not an - * array of numbers, an optional accessor function <tt>f</tt> can be specified - * to map the elements to numbers. See {@link #normalize} for an example. - * Accessor functions can refer to <tt>this.index</tt>. - * - * @param {array} array an array of objects, or numbers. - * @param {function} [f] an optional accessor function. - * @returns {number} the median of the specified array. - */ -pv.median = function(array, f) { - if (f == pv.index) return (array.length - 1) / 2; - array = map(array, f).sort(pv.naturalOrder); - if (array.length % 2) return array[Math.floor(array.length / 2)]; - var i = array.length / 2; - return (array[i - 1] + array[i]) / 2; -}; - -/** - * Returns a map constructed from the specified <tt>keys</tt>, using the - * function <tt>f</tt> to compute the value for each key. The single argument to - * the value function is the key. The callback is invoked only for indexes of - * the array which have assigned values; it is not invoked for indexes which - * have been deleted or which have never been assigned values. - * - * <p>For example, this expression creates a map from strings to string length: - * - * <pre>pv.dict(["one", "three", "seventeen"], function(s) s.length)</pre> - * - * The returned value is <tt>{one: 3, three: 5, seventeen: 9}</tt>. Accessor - * functions can refer to <tt>this.index</tt>. - * - * @param {array} keys an array. - * @param {function} f a value function. - * @returns a map from keys to values. - */ -pv.dict = function(keys, f) { - var m = {}, o = {}; - for (var i = 0; i < keys.length; i++) { - if (i in keys) { - var k = keys[i]; - o.index = i; - m[k] = f.call(o, k); - } - } - return m; -}; - -/** - * Returns a permutation of the specified array, using the specified array of - * indexes. The returned array contains the corresponding element in - * <tt>array</tt> for each index in <tt>indexes</tt>, in order. For example, - * - * <pre>pv.permute(["a", "b", "c"], [1, 2, 0])</pre> - * - * returns <tt>["b", "c", "a"]</tt>. It is acceptable for the array of indexes - * to be a different length from the array of elements, and for indexes to be - * duplicated or omitted. The optional accessor function <tt>f</tt> can be used - * to perform a simultaneous mapping of the array elements. Accessor functions - * can refer to <tt>this.index</tt>. - * - * @param {array} array an array. - * @param {number[]} indexes an array of indexes into <tt>array</tt>. - * @param {function} [f] an optional accessor function. - * @returns {array} an array of elements from <tt>array</tt>; a permutation. - */ -pv.permute = function(array, indexes, f) { - if (!f) f = pv.identity; - var p = new Array(indexes.length), o = {}; - indexes.forEach(function(j, i) { o.index = j; p[i] = f.call(o, array[j]); }); - return p; -}; - -/** - * Returns a map from key to index for the specified <tt>keys</tt> array. For - * example, - * - * <pre>pv.numerate(["a", "b", "c"])</pre> - * - * returns <tt>{a: 0, b: 1, c: 2}</tt>. Note that since JavaScript maps only - * support string keys, <tt>keys</tt> must contain strings, or other values that - * naturally map to distinct string values. Alternatively, an optional accessor - * function <tt>f</tt> can be specified to compute the string key for the given - * element. Accessor functions can refer to <tt>this.index</tt>. - * - * @param {array} keys an array, usually of string keys. - * @param {function} [f] an optional key function. - * @returns a map from key to index. - */ -pv.numerate = function(keys, f) { - if (!f) f = pv.identity; - var map = {}, o = {}; - keys.forEach(function(x, i) { o.index = i; map[f.call(o, x)] = i; }); - return map; -}; - -/** - * The comparator function for natural order. This can be used in conjunction with - * the built-in array <tt>sort</tt> method to sort elements by their natural - * order, ascending. Note that if no comparator function is specified to the - * built-in <tt>sort</tt> method, the default order is lexicographic, <i>not</i> - * natural! - * - * @see <a - * href="http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/sort">Array.sort</a>. - * @param a an element to compare. - * @param b an element to compare. - * @returns {number} negative if a < b; positive if a > b; otherwise 0. - */ -pv.naturalOrder = function(a, b) { - return (a < b) ? -1 : ((a > b) ? 1 : 0); -}; - -/** - * The comparator function for reverse natural order. This can be used in - * conjunction with the built-in array <tt>sort</tt> method to sort elements by - * their natural order, descending. Note that if no comparator function is - * specified to the built-in <tt>sort</tt> method, the default order is - * lexicographic, <i>not</i> natural! - * - * @see #naturalOrder - * @param a an element to compare. - * @param b an element to compare. - * @returns {number} negative if a < b; positive if a > b; otherwise 0. - */ -pv.reverseOrder = function(b, a) { - return (a < b) ? -1 : ((a > b) ? 1 : 0); -}; - -/** - * @private Computes the value of the specified CSS property <tt>p</tt> on the - * specified element <tt>e</tt>. - * - * @param {string} p the name of the CSS property. - * @param e the element on which to compute the CSS property. - */ -pv.css = function(e, p) { - return window.getComputedStyle - ? window.getComputedStyle(e, null).getPropertyValue(p) - : e.currentStyle[p]; -}; - -/** - * Namespace constants for SVG, XMLNS, and XLINK. - * - * @namespace Namespace constants for SVG, XMLNS, and XLINK. - */ -pv.ns = { - /** - * The SVG namespace, "http://www.w3.org/2000/svg". - * - * @type string - * @constant - */ - svg: "http://www.w3.org/2000/svg", - - /** - * The XMLNS namespace, "http://www.w3.org/2000/xmlns". - * - * @type string - * @constant - */ - xmlns: "http://www.w3.org/2000/xmlns", - - /** - * The XLINK namespace, "http://www.w3.org/1999/xlink". - * - * @type string - * @constant - */ - xlink: "http://www.w3.org/1999/xlink" -}; - -/** - * Protovis major and minor version numbers. - * - * @namespace Protovis major and minor version numbers. - */ -pv.version = { - /** - * The major version number. - * - * @type number - * @constant - */ - major: 3, - - /** - * The minor version number. - * - * @type number - * @constant - */ - minor: 1 -}; - -/** - * @private Reports the specified error to the JavaScript console. Mozilla only - * allows logging to the console for privileged code; if the console is - * unavailable, the alert dialog box is used instead. - * - * @param e the exception that triggered the error. - */ -pv.error = function(e) { - (typeof console == "undefined") ? alert(e) : console.error(e); -}; - -/** - * @private Registers the specified listener for events of the specified type on - * the specified target. For standards-compliant browsers, this method uses - * <tt>addEventListener</tt>; for Internet Explorer, <tt>attachEvent</tt>. - * - * @param target a DOM element. - * @param {string} type the type of event, such as "click". - * @param {function} the listener callback function. - */ -pv.listen = function(target, type, listener) { - return target.addEventListener - ? target.addEventListener(type, listener, false) - : target.attachEvent("on" + type, listener); -}; - -/** - * Returns the logarithm with a given base value. - * - * @param {number} x the number for which to compute the logarithm. - * @param {number} b the base of the logarithm. - * @returns {number} the logarithm value. - */ -pv.log = function(x, b) { - return Math.log(x) / Math.log(b); -}; - -/** - * Computes a zero-symmetric logarithm. Computes the logarithm of the absolute - * value of the input, and determines the sign of the output according to the - * sign of the input value. - * - * @param {number} x the number for which to compute the logarithm. - * @param {number} b the base of the logarithm. - * @returns {number} the symmetric log value. - */ -pv.logSymmetric = function(x, b) { - return (x == 0) ? 0 : ((x < 0) ? -pv.log(-x, b) : pv.log(x, b)); -}; - -/** - * Computes a zero-symmetric logarithm, with adjustment to values between zero - * and the logarithm base. This adjustment introduces distortion for values less - * than the base number, but enables simultaneous plotting of log-transformed - * data involving both positive and negative numbers. - * - * @param {number} x the number for which to compute the logarithm. - * @param {number} b the base of the logarithm. - * @returns {number} the adjusted, symmetric log value. - */ -pv.logAdjusted = function(x, b) { - var negative = x < 0; - if (x < b) x += (b - x) / b; - return negative ? -pv.log(x, b) : pv.log(x, b); -}; - -/** - * Rounds an input value down according to its logarithm. The method takes the - * floor of the logarithm of the value and then uses the resulting value as an - * exponent for the base value. - * - * @param {number} x the number for which to compute the logarithm floor. - * @param {number} b the base of the logarithm. - * @return {number} the rounded-by-logarithm value. - */ -pv.logFloor = function(x, b) { - return (x > 0) - ? Math.pow(b, Math.floor(pv.log(x, b))) - : -Math.pow(b, -Math.floor(-pv.log(-x, b))); -}; - -/** - * Rounds an input value up according to its logarithm. The method takes the - * ceiling of the logarithm of the value and then uses the resulting value as an - * exponent for the base value. - * - * @param {number} x the number for which to compute the logarithm ceiling. - * @param {number} b the base of the logarithm. - * @return {number} the rounded-by-logarithm value. - */ -pv.logCeil = function(x, b) { - return (x > 0) - ? Math.pow(b, Math.ceil(pv.log(x, b))) - : -Math.pow(b, -Math.ceil(-pv.log(-x, b))); -}; - -/** - * Searches the specified array of numbers for the specified value using the - * binary search algorithm. The array must be sorted (as by the <tt>sort</tt> - * method) prior to making this call. If it is not sorted, the results are - * undefined. If the array contains multiple elements with the specified value, - * there is no guarantee which one will be found. - * - * <p>The <i>insertion point</i> is defined as the point at which the value - * would be inserted into the array: the index of the first element greater than - * the value, or <tt>array.length</tt>, if all elements in the array are less - * than the specified value. Note that this guarantees that the return value - * will be nonnegative if and only if the value is found. - * - * @param {number[]} array the array to be searched. - * @param {number} value the value to be searched for. - * @returns the index of the search value, if it is contained in the array; - * otherwise, (-(<i>insertion point</i>) - 1). - * @param {function} [f] an optional key function. - */ -pv.search = function(array, value, f) { - if (!f) f = pv.identity; - var low = 0, high = array.length - 1; - while (low <= high) { - var mid = (low + high) >> 1, midValue = f(array[mid]); - if (midValue < value) low = mid + 1; - else if (midValue > value) high = mid - 1; - else return mid; - } - return -low - 1; -}; - -pv.search.index = function(array, value, f) { - var i = pv.search(array, value, f); - return (i < 0) ? (-i - 1) : i; -}; -/** - * Returns a {@link pv.Tree} operator for the specified array. This is a - * convenience factory method, equivalent to <tt>new pv.Tree(array)</tt>. - * - * @see pv.Tree - * @param {array} array an array from which to construct a tree. - * @returns {pv.Tree} a tree operator for the specified array. - */ -pv.tree = function(array) { - return new pv.Tree(array); -}; - -/** - * Constructs a tree operator for the specified array. This constructor should - * not be invoked directly; use {@link pv.tree} instead. - * - * @class Represents a tree operator for the specified array. The tree operator - * allows a hierarchical map to be constructed from an array; it is similar to - * the {@link pv.Nest} operator, except the hierarchy is derived dynamically - * from the array elements. - * - * <p>For example, given an array of size information for ActionScript classes: - * - * <pre>{ name: "flare.flex.FlareVis", size: 4116 }, - * { name: "flare.physics.DragForce", size: 1082 }, - * { name: "flare.physics.GravityForce", size: 1336 }, ...</pre> - * - * To facilitate visualization, it may be useful to nest the elements by their - * package hierarchy: - * - * <pre>var tree = pv.tree(classes) - * .keys(function(d) d.name.split(".")) - * .map();</pre> - * - * The resulting tree is: - * - * <pre>{ flare: { - * flex: { - * FlareVis: { - * name: "flare.flex.FlareVis", - * size: 4116 } }, - * physics: { - * DragForce: { - * name: "flare.physics.DragForce", - * size: 1082 }, - * GravityForce: { - * name: "flare.physics.GravityForce", - * size: 1336 } }, - * ... } }</pre> - * - * By specifying a value function, - * - * <pre>var tree = pv.tree(classes) - * .keys(function(d) d.name.split(".")) - * .value(function(d) d.size) - * .map();</pre> - * - * we can further eliminate redundant data: - * - * <pre>{ flare: { - * flex: { - * FlareVis: 4116 }, - * physics: { - * DragForce: 1082, - * GravityForce: 1336 }, - * ... } }</pre> - * - * For visualizations with large data sets, performance improvements may be seen - * by storing the data in a tree format, and then flattening it into an array at - * runtime with {@link pv.Flatten}. - * - * @param {array} array an array from which to construct a tree. - */ -pv.Tree = function(array) { - this.array = array; -}; - -/** - * Assigns a <i>keys</i> function to this operator; required. The keys function - * returns an array of <tt>string</tt>s for each element in the associated - * array; these keys determine how the elements are nested in the tree. The - * returned keys should be unique for each element in the array; otherwise, the - * behavior of this operator is undefined. - * - * @param {function} k the keys function. - * @returns {pv.Tree} this. - */ -pv.Tree.prototype.keys = function(k) { - this.k = k; - return this; -}; - -/** - * Assigns a <i>value</i> function to this operator; optional. The value - * function specifies an optional transformation of the element in the array - * before it is inserted into the map. If no value function is specified, it is - * equivalent to using the identity function. - * - * @param {function} k the value function. - * @returns {pv.Tree} this. - */ -pv.Tree.prototype.value = function(v) { - this.v = v; - return this; -}; - -/** - * Returns a hierarchical map of values. The hierarchy is determined by the keys - * function; the values in the map are determined by the value function. - * - * @returns a hierarchical map of values. - */ -pv.Tree.prototype.map = function() { - var map = {}, o = {}; - for (var i = 0; i < this.array.length; i++) { - o.index = i; - var value = this.array[i], keys = this.k.call(o, value), node = map; - for (var j = 0; j < keys.length - 1; j++) { - node = node[keys[j]] || (node[keys[j]] = {}); - } - node[keys[j]] = this.v ? this.v.call(o, value) : value; - } - return map; -}; -/** - * Returns a {@link pv.Nest} operator for the specified array. This is a - * convenience factory method, equivalent to <tt>new pv.Nest(array)</tt>. - * - * @see pv.Nest - * @param {array} array an array of elements to nest. - * @returns {pv.Nest} a nest operator for the specified array. - */ -pv.nest = function(array) { - return new pv.Nest(array); -}; - -/** - * Constructs a nest operator for the specified array. This constructor should - * not be invoked directly; use {@link pv.nest} instead. - * - * @class Represents a {@link Nest} operator for the specified array. Nesting - * allows elements in an array to be grouped into a hierarchical tree - * structure. The levels in the tree are specified by <i>key</i> functions. The - * leaf nodes of the tree can be sorted by value, while the internal nodes can - * be sorted by key. Finally, the tree can be returned either has a - * multidimensional array via {@link #entries}, or as a hierarchical map via - * {@link #map}. The {@link #rollup} routine similarly returns a map, collapsing - * the elements in each leaf node using a summary function. - * - * <p>For example, consider the following tabular data structure of Barley - * yields, from various sites in Minnesota during 1931-2: - * - * <pre>{ yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm" }, - * { yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca" }, - * { yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris" }, ...</pre> - * - * To facilitate visualization, it may be useful to nest the elements first by - * year, and then by variety, as follows: - * - * <pre>var nest = pv.nest(yields) - * .key(function(d) d.year) - * .key(function(d) d.variety) - * .entries();</pre> - * - * This returns a nested array. Each element of the outer array is a key-values - * pair, listing the values for each distinct key: - * - * <pre>{ key: 1931, values: [ - * { key: "Manchuria", values: [ - * { yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm" }, - * { yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca" }, - * { yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris" }, - * ... - * ] }, - * { key: "Glabron", values: [ - * { yield: 43.07, variety: "Glabron", year: 1931, site: "University Farm" }, - * { yield: 55.20, variety: "Glabron", year: 1931, site: "Waseca" }, - * ... - * ] }, - * ] }, - * { key: 1932, values: ... }</pre> - * - * Further details, including sorting and rollup, is provided below on the - * corresponding methods. - * - * @param {array} array an array of elements to nest. - */ -pv.Nest = function(array) { - this.array = array; - this.keys = []; -}; - -/** - * Nests using the specified key function. Multiple keys may be added to the - * nest; the array elements will be nested in the order keys are specified. - * - * @param {function} key a key function; must return a string or suitable map - * key. - * @return {pv.Nest} this. - */ -pv.Nest.prototype.key = function(key) { - this.keys.push(key); - return this; -}; - -/** - * Sorts the previously-added keys. The natural sort order is used by default - * (see {@link pv.naturalOrder}); if an alternative order is desired, - * <tt>order</tt> should be a comparator function. If this method is not called - * (i.e., keys are <i>unsorted</i>), keys will appear in the order they appear - * in the underlying elements array. For example, - * - * <pre>pv.nest(yields) - * .key(function(d) d.year) - * .key(function(d) d.variety) - * .sortKeys() - * .entries()</pre> - * - * groups yield data by year, then variety, and sorts the variety groups - * lexicographically (since the variety attribute is a string). - * - * <p>Key sort order is only used in conjunction with {@link #entries}, which - * returns an array of key-values pairs. If the nest is used to construct a - * {@link #map} instead, keys are unsorted. - * - * @param {function} [order] an optional comparator function. - * @returns {pv.Nest} this. - */ -pv.Nest.prototype.sortKeys = function(order) { - this.keys[this.keys.length - 1].order = order || pv.naturalOrder; - return this; -}; - -/** - * Sorts the leaf values. The natural sort order is used by default (see - * {@link pv.naturalOrder}); if an alternative order is desired, <tt>order</tt> - * should be a comparator function. If this method is not called (i.e., values - * are <i>unsorted</i>), values will appear in the order they appear in the - * underlying elements array. For example, - * - * <pre>pv.nest(yields) - * .key(function(d) d.year) - * .key(function(d) d.variety) - * .sortValues(function(a, b) a.yield - b.yield) - * .entries()</pre> - * - * groups yield data by year, then variety, and sorts the values for each - * variety group by yield. - * - * <p>Value sort order, unlike keys, applies to both {@link #entries} and - * {@link #map}. It has no effect on {@link #rollup}. - * - * @param {function} [order] an optional comparator function. - * @return {pv.Nest} this. - */ -pv.Nest.prototype.sortValues = function(order) { - this.order = order || pv.naturalOrder; - return this; -}; - -/** - * Returns a hierarchical map of values. Each key adds one level to the - * hierarchy. With only a single key, the returned map will have a key for each - * distinct value of the key function; the correspond value with be an array of - * elements with that key value. If a second key is added, this will be a nested - * map. For example: - * - * <pre>pv.nest(yields) - * .key(function(d) d.variety) - * .key(function(d) d.site) - * .map()</pre> - * - * returns a map <tt>m</tt> such that <tt>m[variety][site]</tt> is an array, a subset of - * <tt>yields</tt>, with each element having the given variety and site. - * - * @returns a hierarchical map of values. - */ -pv.Nest.prototype.map = function() { - var map = {}, values = []; - - /* Build the map. */ - for (var i, j = 0; j < this.array.length; j++) { - var x = this.array[j]; - var m = map; - for (i = 0; i < this.keys.length - 1; i++) { - var k = this.keys[i](x); - if (!m[k]) m[k] = {}; - m = m[k]; - } - k = this.keys[i](x); - if (!m[k]) { - var a = []; - values.push(a); - m[k] = a; - } - m[k].push(x); - } - - /* Sort each leaf array. */ - if (this.order) { - for (var i = 0; i < values.length; i++) { - values[i].sort(this.order); - } - } - - return map; -}; - -/** - * Returns a hierarchical nested array. This method is similar to - * {@link pv.entries}, but works recursively on the entire hierarchy. Rather - * than returning a map like {@link #map}, this method returns a nested - * array. Each element of the array has a <tt>key</tt> and <tt>values</tt> - * field. For leaf nodes, the <tt>values</tt> array will be a subset of the - * underlying elements array; for non-leaf nodes, the <tt>values</tt> array will - * contain more key-values pairs. - * - * <p>For an example usage, see the {@link Nest} constructor. - * - * @returns a hierarchical nested array. - */ -pv.Nest.prototype.entries = function() { - - /** Recursively extracts the entries for the given map. */ - function entries(map) { - var array = []; - for (var k in map) { - var v = map[k]; - array.push({ key: k, values: (v instanceof Array) ? v : entries(v) }); - }; - return array; - } - - /** Recursively sorts the values for the given key-values array. */ - function sort(array, i) { - var o = this.keys[i].order; - if (o) array.sort(function(a, b) { return o(a.key, b.key); }); - if (++i < this.keys.length) { - for (var j = 0; j < array.length; j++) { - sort.call(this, array[j].values, i); - } - } - return array; - } - - return sort.call(this, entries(this.map()), 0); -}; - -/** - * Returns a rollup map. The behavior of this method is the same as - * {@link #map}, except that the leaf values are replaced with the return value - * of the specified rollup function <tt>f</tt>. For example, - * - * <pre>pv.nest(yields) - * .key(function(d) d.site) - * .rollup(function(v) pv.median(v, function(d) d.yield))</pre> - * - * first groups yield data by site, and then returns a map from site to median - * yield for the given site. - * - * @see #map - * @param {function} f a rollup function. - * @returns a hierarchical map, with the leaf values computed by <tt>f</tt>. - */ -pv.Nest.prototype.rollup = function(f) { - - /** Recursively descends to the leaf nodes (arrays) and does rollup. */ - function rollup(map) { - for (var key in map) { - var value = map[key]; - if (value instanceof Array) { - map[key] = f(value); - } else { - rollup(value); - } - } - return map; - } - - return rollup(this.map()); -}; -/** - * Returns a {@link pv.Flatten} operator for the specified map. This is a - * convenience factory method, equivalent to <tt>new pv.Flatten(map)</tt>. - * - * @see pv.Flatten - * @param map a map to flatten. - * @returns {pv.Flatten} a flatten operator for the specified map. - */ -pv.flatten = function(map) { - return new pv.Flatten(map); -}; - -/** - * Constructs a flatten operator for the specified map. This constructor should - * not be invoked directly; use {@link pv.flatten} instead. - * - * @class Represents a flatten operator for the specified array. Flattening - * allows hierarchical maps to be flattened into an array. The levels in the - * input tree are specified by <i>key</i> functions. - * - * <p>For example, consider the following hierarchical data structure of Barley - * yields, from various sites in Minnesota during 1931-2: - * - * <pre>{ 1931: { - * Manchuria: { - * "University Farm": 27.00, - * "Waseca": 48.87, - * "Morris": 27.43, - * ... }, - * Glabron: { - * "University Farm": 43.07, - * "Waseca": 55.20, - * ... } }, - * 1932: { - * ... } }</pre> - * - * To facilitate visualization, it may be useful to flatten the tree into a - * tabular array: - * - * <pre>var array = pv.flatten(yields) - * .key("year") - * .key("variety") - * .key("site") - * .key("yield") - * .array();</pre> - * - * This returns an array of object elements. Each element in the array has - * attributes corresponding to this flatten operator's keys: - * - * <pre>{ site: "University Farm", variety: "Manchuria", year: 1931, yield: 27 }, - * { site: "Waseca", variety: "Manchuria", year: 1931, yield: 48.87 }, - * { site: "Morris", variety: "Manchuria", year: 1931, yield: 27.43 }, - * { site: "University Farm", variety: "Glabron", year: 1931, yield: 43.07 }, - * { site: "Waseca", variety: "Glabron", year: 1931, yield: 55.2 }, ...</pre> - * - * <p>The flatten operator is roughly the inverse of the {@link pv.Nest} and - * {@link pv.Tree} operators. - * - * @param map a map to flatten. - */ -pv.Flatten = function(map) { - this.map = map; - this.keys = []; -}; - -/** - * Flattens using the specified key function. Multiple keys may be added to the - * flatten; the tiers of the underlying tree must correspond to the specified - * keys, in order. The order of the returned array is undefined; however, you - * can easily sort it. - * - * @param {string} key the key name. - * @param {function} [f] an optional value map function. - * @return {pv.Nest} this. - */ -pv.Flatten.prototype.key = function(key, f) { - this.keys.push({name: key, value: f}); - return this; -}; - -/** - * Returns the flattened array. Each entry in the array is an object; each - * object has attributes corresponding to this flatten operator's keys. - * - * @returns an array of elements from the flattened map. - */ -pv.Flatten.prototype.array = function() { - var entries = [], stack = [], keys = this.keys; - - /* Recursively visits the specified value. */ - function visit(value, i) { - if (i < keys.length - 1) { - for (var key in value) { - stack.push(key); - visit(value[key], i + 1); - stack.pop(); - } - } else { - entries.push(stack.concat(value)); - } - } - - visit(this.map, 0); - return entries.map(function(stack) { - var m = {}; - for (var i = 0; i < keys.length; i++) { - var k = keys[i], v = stack[i]; - m[k.name] = k.value ? k.value.call(null, v) : v; - } - return m; - }); -}; -/** - * Returns a {@link pv.Vector} for the specified <i>x</i> and <i>y</i> - * coordinate. This is a convenience factory method, equivalent to <tt>new - * pv.Vector(x, y)</tt>. - * - * @see pv.Vector - * @param {number} x the <i>x</i> coordinate. - * @param {number} y the <i>y</i> coordinate. - * @returns {pv.Vector} a vector for the specified coordinates. - */ -pv.vector = function(x, y) { - return new pv.Vector(x, y); -}; - -/** - * Constructs a {@link pv.Vector} for the specified <i>x</i> and <i>y</i> - * coordinate. This constructor should not be invoked directly; use - * {@link pv.vector} instead. - * - * @class Represents a two-dimensional vector; a 2-tuple <i>⟨x, - * y⟩</i>. - * - * @param {number} x the <i>x</i> coordinate. - * @param {number} y the <i>y</i> coordinate. - */ -pv.Vector = function(x, y) { - this.x = x; - this.y = y; -}; - -/** - * Returns a vector perpendicular to this vector: <i>⟨-y, x⟩</i>. - * - * @returns {pv.Vector} a perpendicular vector. - */ -pv.Vector.prototype.perp = function() { - return new pv.Vector(-this.y, this.x); -}; - -/** - * Returns a normalized copy of this vector: a vector with the same direction, - * but unit length. If this vector has zero length this method returns a copy of - * this vector. - * - * @returns {pv.Vector} a unit vector. - */ -pv.Vector.prototype.norm = function() { - var l = this.length(); - return this.times(l ? (1 / l) : 1); -}; - -/** - * Returns the magnitude of this vector, defined as <i>sqrt(x * x + y * y)</i>. - * - * @returns {number} a length. - */ -pv.Vector.prototype.length = function() { - return Math.sqrt(this.x * this.x + this.y * this.y); -}; - -/** - * Returns a scaled copy of this vector: <i>⟨x * k, y * k⟩</i>. - * To perform the equivalent divide operation, use <i>1 / k</i>. - * - * @param {number} k the scale factor. - * @returns {pv.Vector} a scaled vector. - */ -pv.Vector.prototype.times = function(k) { - return new pv.Vector(this.x * k, this.y * k); -}; - -/** - * Returns this vector plus the vector <i>v</i>: <i>⟨x + v.x, y + - * v.y⟩</i>. If only one argument is specified, it is interpreted as the - * vector <i>v</i>. - * - * @param {number} x the <i>x</i> coordinate to add. - * @param {number} y the <i>y</i> coordinate to add. - * @returns {pv.Vector} a new vector. - */ -pv.Vector.prototype.plus = function(x, y) { - return (arguments.length == 1) - ? new pv.Vector(this.x + x.x, this.y + x.y) - : new pv.Vector(this.x + x, this.y + y); -}; - -/** - * Returns this vector minus the vector <i>v</i>: <i>⟨x - v.x, y - - * v.y⟩</i>. If only one argument is specified, it is interpreted as the - * vector <i>v</i>. - * - * @param {number} x the <i>x</i> coordinate to subtract. - * @param {number} y the <i>y</i> coordinate to subtract. - * @returns {pv.Vector} a new vector. - */ -pv.Vector.prototype.minus = function(x, y) { - return (arguments.length == 1) - ? new pv.Vector(this.x - x.x, this.y - x.y) - : new pv.Vector(this.x - x, this.y - y); -}; - -/** - * Returns the dot product of this vector and the vector <i>v</i>: <i>x * v.x + - * y * v.y</i>. If only one argument is specified, it is interpreted as the - * vector <i>v</i>. - * - * @param {number} x the <i>x</i> coordinate to dot. - * @param {number} y the <i>y</i> coordinate to dot. - * @returns {number} a dot product. - */ -pv.Vector.prototype.dot = function(x, y) { - return (arguments.length == 1) - ? this.x * x.x + this.y * x.y - : this.x * x + this.y * y; -}; -// TODO code-sharing between scales - -/** - * @ignore - * @class - */ -pv.Scale = function() {}; - -/** - * @private Returns a function that interpolators from the start value to the - * end value, given a parameter <i>t</i> in [0, 1]. - * - * @param start the start value. - * @param end the end value. - */ -pv.Scale.interpolator = function(start, end) { - if (typeof start == "number") { - return function(t) { - return t * (end - start) + start; - }; - } - - /* For now, assume color. */ - start = pv.color(start).rgb(); - end = pv.color(end).rgb(); - return function(t) { - var a = start.a * (1 - t) + end.a * t; - if (a < 1e-5) a = 0; // avoid scientific notation - return (start.a == 0) ? pv.rgb(end.r, end.g, end.b, a) - : ((end.a == 0) ? pv.rgb(start.r, start.g, start.b, a) - : pv.rgb( - Math.round(start.r * (1 - t) + end.r * t), - Math.round(start.g * (1 - t) + end.g * t), - Math.round(start.b * (1 - t) + end.b * t), a)); - }; -}; -/** - * Returns a linear scale for the specified domain. The arguments to this - * constructor are optional, and equivalent to calling {@link #domain}. - * - * @class Represents a linear scale. <style - * type="text/css">sub{line-height:0}</style> <img src="../linear.png" - * width="180" height="175" align="right"> Most commonly, a linear scale - * represents a 1-dimensional linear transformation from a numeric domain of - * input data [<i>d<sub>0</sub></i>, <i>d<sub>1</sub></i>] to a numeric range of - * pixels [<i>r<sub>0</sub></i>, <i>r<sub>1</sub></i>]. The equation for such a - * scale is: - * - * <blockquote><i>f(x) = (x - d<sub>0</sub>) / (d<sub>1</sub> - d<sub>0</sub>) * - * (r<sub>1</sub> - r<sub>0</sub>) + r<sub>0</sub></i></blockquote> - * - * For example, a linear scale from the domain [0, 100] to range [0, 640]: - * - * <blockquote><i>f(x) = (x - 0) / (100 - 0) * (640 - 0) + 0</i><br> - * <i>f(x) = x / 100 * 640</i><br> - * <i>f(x) = x * 6.4</i><br> - * </blockquote> - * - * Thus, saying - * - * <pre>.height(function(d) d * 6.4)</pre> - * - * is identical to - * - * <pre>.height(pv.Scale.linear(0, 100).range(0, 640))</pre> - * - * As you can see, scales do not always make code smaller, but they should make - * code more explicit and easier to maintain. In addition to readability, scales - * offer several useful features: - * - * <p>1. The range can be expressed in colors, rather than pixels. Changing the - * example above to - * - * <pre>.fillStyle(pv.Scale.linear(0, 100).range("red", "green"))</pre> - * - * will cause it to fill the marks "red" on an input value of 0, "green" on an - * input value of 100, and some color in-between for intermediate values. - * - * <p>2. The domain and range can be subdivided for a "poly-linear" - * transformation. For example, you may want a diverging color scale that is - * increasingly red for negative values, and increasingly green for positive - * values: - * - * <pre>.fillStyle(pv.Scale.linear(-1, 0, 1).range("red", "white", "green"))</pre> - * - * The domain can be specified as a series of <i>n</i> monotonically-increasing - * values; the range must also be specified as <i>n</i> values, resulting in - * <i>n - 1</i> contiguous linear scales. - * - * <p>3. Linear scales can be inverted for interaction. The {@link #invert} - * method takes a value in the output range, and returns the corresponding value - * in the input domain. This is frequently used to convert the mouse location - * (see {@link pv.Mark#mouse}) to a value in the input domain. Note that - * inversion is only supported for numeric ranges, and not colors. - * - * <p>4. A scale can be queried for reasonable "tick" values. The {@link #ticks} - * method provides a convenient way to get a series of evenly-spaced rounded - * values in the input domain. Frequently these are used in conjunction with - * {@link pv.Rule} to display tick marks or grid lines. - * - * <p>5. A scale can be "niced" to extend the domain to suitable rounded - * numbers. If the minimum and maximum of the domain are messy because they are - * derived from data, you can use {@link #nice} to round these values down and - * up to even numbers. - * - * @param {number...} domain... domain values. - * @returns {pv.Scale.linear} a linear scale. - */ -pv.Scale.linear = function() { - var d = [0, 1], r = [0, 1], i = [pv.identity], precision = 0; - - /** @private */ - function scale(x) { - var j = pv.search(d, x); - if (j < 0) j = -j - 2; - j = Math.max(0, Math.min(i.length - 1, j)); - return i[j]((x - d[j]) / (d[j + 1] - d[j])); - } - - /** - * Sets or gets the input domain. This method can be invoked several ways: - * - * <p>1. <tt>domain(min, ..., max)</tt> - * - * <p>Specifying the domain as a series of numbers is the most explicit and - * recommended approach. Most commonly, two numbers are specified: the minimum - * and maximum value. However, for a diverging scale, or other subdivided - * poly-linear scales, multiple values can be specified. Values can be derived - * from data using {@link pv.min} and {@link pv.max}. For example: - * - * <pre>.domain(0, pv.max(array))</pre> - * - * An alternative method for deriving minimum and maximum values from data - * follows. - * - * <p>2. <tt>domain(array, minf, maxf)</tt> - * - * <p>When both the minimum and maximum value are derived from data, the - * arguments to the <tt>domain</tt> method can be specified as the array of - * data, followed by zero, one or two accessor functions. For example, if the - * array of data is just an array of numbers: - * - * <pre>.domain(array)</pre> - * - * On the other hand, if the array elements are objects representing stock - * values per day, and the domain should consider the stock's daily low and - * daily high: - * - * <pre>.domain(array, function(d) d.low, function(d) d.high)</pre> - * - * The first method of setting the domain is preferred because it is more - * explicit; setting the domain using this second method should be used only - * if brevity is required. - * - * <p>3. <tt>domain()</tt> - * - * <p>Invoking the <tt>domain</tt> method with no arguments returns the - * current domain as an array of numbers. - * - * @function - * @name pv.Scale.linear.prototype.domain - * @param {number...} domain... domain values. - * @returns {pv.Scale.linear} <tt>this</tt>, or the current domain. - */ - scale.domain = function(array, min, max) { - if (arguments.length) { - if (array instanceof Array) { - if (arguments.length < 2) min = pv.identity; - if (arguments.length < 3) max = min; - d = [pv.min(array, min), pv.max(array, max)]; - } else { - d = Array.prototype.slice.call(arguments); - } - return this; - } - return d; - }; - - /** - * Sets or gets the output range. This method can be invoked several ways: - * - * <p>1. <tt>range(min, ..., max)</tt> - * - * <p>The range may be specified as a series of numbers or colors. Most - * commonly, two numbers are specified: the minimum and maximum pixel values. - * For a color scale, values may be specified as {@link pv.Color}s or - * equivalent strings. For a diverging scale, or other subdivided poly-linear - * scales, multiple values can be specified. For example: - * - * <pre>.range("red", "white", "green")</pre> - * - * <p>Currently, only numbers and colors are supported as range values. The - * number of range values must exactly match the number of domain values, or - * the behavior of the scale is undefined. - * - * <p>2. <tt>range()</tt> - * - * <p>Invoking the <tt>range</tt> method with no arguments returns the current - * range as an array of numbers or colors. - * - * @function - * @name pv.Scale.linear.prototype.range - * @param {...} range... range values. - * @returns {pv.Scale.linear} <tt>this</tt>, or the current range. - */ - scale.range = function() { - if (arguments.length) { - r = Array.prototype.slice.call(arguments); - i = []; - for (var j = 0; j < r.length - 1; j++) { - i.push(pv.Scale.interpolator(r[j], r[j + 1])); - } - return this; - } - return r; - }; - - /** - * Inverts the specified value in the output range, returning the - * corresponding value in the input domain. This is frequently used to convert - * the mouse location (see {@link pv.Mark#mouse}) to a value in the input - * domain. Inversion is only supported for numeric ranges, and not colors. - * - * <p>Note that this method does not do any rounding or bounds checking. If - * the input domain is discrete (e.g., an array index), the returned value - * should be rounded. If the specified <tt>y</tt> value is outside the range, - * the returned value may be equivalently outside the input domain. - * - * @function - * @name pv.Scale.linear.prototype.invert - * @param {number} y a value in the output range (a pixel location). - * @returns {number} a value in the input domain. - */ - scale.invert = function(y) { - var j = pv.search(r, y); - if (j < 0) j = -j - 2; - j = Math.max(0, Math.min(i.length - 1, j)); - return (y - r[j]) / (r[j + 1] - r[j]) * (d[j + 1] - d[j]) + d[j]; - }; - - /** - * Returns an array of evenly-spaced, suitably-rounded values in the input - * domain. This method attempts to return between 5 and 10 tick values. These - * values are frequently used in conjunction with {@link pv.Rule} to display - * tick marks or grid lines. - * - * @function - * @name pv.Scale.linear.prototype.ticks - * @returns {number[]} an array input domain values to use as ticks. - */ - scale.ticks = function() { - var min = d[0], - max = d[d.length - 1], - span = max - min, - step = pv.logCeil(span / 10, 10); - if (span / step < 2) step /= 5; - else if (span / step < 5) step /= 2; - var start = Math.ceil(min / step) * step, - end = Math.floor(max / step) * step; - precision = Math.max(0, -Math.floor(pv.log(step, 10) + .01)); - return pv.range(start, end + step, step); - }; - - /** - * Formats the specified tick value using the appropriate precision, based on - * the step interval between tick marks. - * - * @function - * @name pv.Scale.linear.prototype.tickFormat - * @param {number} t a tick value. - * @return {string} a formatted tick value. - */ - scale.tickFormat = function(t) { - return t.toFixed(precision); - }; - - /** - * "Nices" this scale, extending the bounds of the input domain to - * evenly-rounded values. Nicing is useful if the domain is computed - * dynamically from data, and may be irregular. For example, given a domain of - * [0.20147987687960267, 0.996679553296417], a call to <tt>nice()</tt> might - * extend the domain to [0.2, 1]. - * - * <p>This method must be invoked each time after setting the domain. - * - * @function - * @name pv.Scale.linear.prototype.nice - * @returns {pv.Scale.linear} <tt>this</tt>. - */ - scale.nice = function() { - var min = d[0], - max = d[d.length - 1], - step = Math.pow(10, Math.round(Math.log(max - min) / Math.log(10)) - 1); - d = [Math.floor(min / step) * step, Math.ceil(max / step) * step]; - return this; - }; - - /** - * Returns a view of this scale by the specified accessor function <tt>f</tt>. - * Given a scale <tt>y</tt>, <tt>y.by(function(d) d.foo)</tt> is equivalent to - * <tt>function(d) y(d.foo)</tt>. - * - * <p>This method is provided for convenience, such that scales can be - * succinctly defined inline. For example, given an array of data elements - * that have a <tt>score</tt> attribute with the domain [0, 1], the height - * property could be specified as: - * - * <pre>.height(pv.Scale.linear().range(0, 480).by(function(d) d.score))</pre> - * - * This is equivalent to: - * - * <pre>.height(function(d) d.score * 480)</pre> - * - * This method should be used judiciously; it is typically more clear to - * invoke the scale directly, passing in the value to be scaled. - * - * @function - * @name pv.Scale.linear.prototype.by - * @param {function} f an accessor function. - * @returns {pv.Scale.linear} a view of this scale by the specified accessor - * function. - */ - scale.by = function(f) { - function by() { return scale(f.apply(this, arguments)); } - for (var method in scale) by[method] = scale[method]; - return by; - }; - - scale.domain.apply(scale, arguments); - return scale; -}; -/** - * Returns a log scale for the specified domain. The arguments to this - * constructor are optional, and equivalent to calling {@link #domain}. - * - * @class Represents a log scale. <style - * type="text/css">sub{line-height:0}</style> <img src="../log.png" - * width="190" height="175" align="right"> Most commonly, a log scale represents - * a 1-dimensional log transformation from a numeric domain of input data - * [<i>d<sub>0</sub></i>, <i>d<sub>1</sub></i>] to a numeric range of pixels - * [<i>r<sub>0</sub></i>, <i>r<sub>1</sub></i>]. The equation for such a scale - * is: - * - * <blockquote><i>f(x) = (log(x) - log(d<sub>0</sub>)) / (log(d<sub>1</sub>) - - * log(d<sub>0</sub>)) * (r<sub>1</sub> - r<sub>0</sub>) + - * r<sub>0</sub></i></blockquote> - * - * where <i>log(x)</i> represents the zero-symmetric logarthim of <i>x</i> using - * the scale's associated base (default: 10, see {@link pv.logSymmetric}). For - * example, a log scale from the domain [1, 100] to range [0, 640]: - * - * <blockquote><i>f(x) = (log(x) - log(1)) / (log(100) - log(1)) * (640 - 0) + 0</i><br> - * <i>f(x) = log(x) / 2 * 640</i><br> - * <i>f(x) = log(x) * 320</i><br> - * </blockquote> - * - * Thus, saying - * - * <pre>.height(function(d) Math.log(d) * 138.974)</pre> - * - * is equivalent to - * - * <pre>.height(pv.Scale.log(1, 100).range(0, 640))</pre> - * - * As you can see, scales do not always make code smaller, but they should make - * code more explicit and easier to maintain. In addition to readability, scales - * offer several useful features: - * - * <p>1. The range can be expressed in colors, rather than pixels. Changing the - * example above to - * - * <pre>.fillStyle(pv.Scale.log(1, 100).range("red", "green"))</pre> - * - * will cause it to fill the marks "red" on an input value of 1, "green" on an - * input value of 100, and some color in-between for intermediate values. - * - * <p>2. The domain and range can be subdivided for a "poly-log" - * transformation. For example, you may want a diverging color scale that is - * increasingly red for small values, and increasingly green for large values: - * - * <pre>.fillStyle(pv.Scale.log(1, 10, 100).range("red", "white", "green"))</pre> - * - * The domain can be specified as a series of <i>n</i> monotonically-increasing - * values; the range must also be specified as <i>n</i> values, resulting in - * <i>n - 1</i> contiguous log scales. - * - * <p>3. Log scales can be inverted for interaction. The {@link #invert} method - * takes a value in the output range, and returns the corresponding value in the - * input domain. This is frequently used to convert the mouse location (see - * {@link pv.Mark#mouse}) to a value in the input domain. Note that inversion is - * only supported for numeric ranges, and not colors. - * - * <p>4. A scale can be queried for reasonable "tick" values. The {@link #ticks} - * method provides a convenient way to get a series of evenly-spaced rounded - * values in the input domain. Frequently these are used in conjunction with - * {@link pv.Rule} to display tick marks or grid lines. - * - * <p>5. A scale can be "niced" to extend the domain to suitable rounded - * numbers. If the minimum and maximum of the domain are messy because they are - * derived from data, you can use {@link #nice} to round these values down and - * up to even numbers. - * - * @param {number...} domain... domain values. - * @returns {pv.Scale.log} a log scale. - */ -pv.Scale.log = function() { - var d = [1, 10], l = [0, 1], b = 10, r = [0, 1], i = [pv.identity]; - - /** @private */ - function scale(x) { - var j = pv.search(d, x); - if (j < 0) j = -j - 2; - j = Math.max(0, Math.min(i.length - 1, j)); - return i[j]((log(x) - l[j]) / (l[j + 1] - l[j])); - } - - /** @private */ - function log(x) { - return pv.logSymmetric(x, b); - } - - /** - * Sets or gets the input domain. This method can be invoked several ways: - * - * <p>1. <tt>domain(min, ..., max)</tt> - * - * <p>Specifying the domain as a series of numbers is the most explicit and - * recommended approach. Most commonly, two numbers are specified: the minimum - * and maximum value. However, for a diverging scale, or other subdivided - * poly-log scales, multiple values can be specified. Values can be derived - * from data using {@link pv.min} and {@link pv.max}. For example: - * - * <pre>.domain(1, pv.max(array))</pre> - * - * An alternative method for deriving minimum and maximum values from data - * follows. - * - * <p>2. <tt>domain(array, minf, maxf)</tt> - * - * <p>When both the minimum and maximum value are derived from data, the - * arguments to the <tt>domain</tt> method can be specified as the array of - * data, followed by zero, one or two accessor functions. For example, if the - * array of data is just an array of numbers: - * - * <pre>.domain(array)</pre> - * - * On the other hand, if the array elements are objects representing stock - * values per day, and the domain should consider the stock's daily low and - * daily high: - * - * <pre>.domain(array, function(d) d.low, function(d) d.high)</pre> - * - * The first method of setting the domain is preferred because it is more - * explicit; setting the domain using this second method should be used only - * if brevity is required. - * - * <p>3. <tt>domain()</tt> - * - * <p>Invoking the <tt>domain</tt> method with no arguments returns the - * current domain as an array of numbers. - * - * @function - * @name pv.Scale.log.prototype.domain - * @param {number...} domain... domain values. - * @returns {pv.Scale.log} <tt>this</tt>, or the current domain. - */ - scale.domain = function(array, min, max) { - if (arguments.length) { - if (array instanceof Array) { - if (arguments.length < 2) min = pv.identity; - if (arguments.length < 3) max = min; - d = [pv.min(array, min), pv.max(array, max)]; - } else { - d = Array.prototype.slice.call(arguments); - } - l = d.map(log); - return this; - } - return d; - }; - - /** - * @function - * @name pv.Scale.log.prototype.range - * @param {...} range... range values. - * @returns {pv.Scale.log} <tt>this</tt>. - */ - scale.range = function() { - if (arguments.length) { - r = Array.prototype.slice.call(arguments); - i = []; - for (var j = 0; j < r.length - 1; j++) { - i.push(pv.Scale.interpolator(r[j], r[j + 1])); - } - return this; - } - return r; - }; - - /** - * Sets or gets the output range. This method can be invoked several ways: - * - * <p>1. <tt>range(min, ..., max)</tt> - * - * <p>The range may be specified as a series of numbers or colors. Most - * commonly, two numbers are specified: the minimum and maximum pixel values. - * For a color scale, values may be specified as {@link pv.Color}s or - * equivalent strings. For a diverging scale, or other subdivided poly-log - * scales, multiple values can be specified. For example: - * - * <pre>.range("red", "white", "green")</pre> - * - * <p>Currently, only numbers and colors are supported as range values. The - * number of range values must exactly match the number of domain values, or - * the behavior of the scale is undefined. - * - * <p>2. <tt>range()</tt> - * - * <p>Invoking the <tt>range</tt> method with no arguments returns the current - * range as an array of numbers or colors. - * - * @function - * @name pv.Scale.log.prototype.invert - * @param {...} range... range values. - * @returns {pv.Scale.log} <tt>this</tt>, or the current range. - */ - scale.invert = function(y) { - var j = pv.search(r, y); - if (j < 0) j = -j - 2; - j = Math.max(0, Math.min(i.length - 1, j)); - var t = l[j] + (y - r[j]) / (r[j + 1] - r[j]) * (l[j + 1] - l[j]); - return (d[j] < 0) ? -Math.pow(b, -t) : Math.pow(b, t); - }; - - /** - * Returns an array of evenly-spaced, suitably-rounded values in the input - * domain. These values are frequently used in conjunction with {@link - * pv.Rule} to display tick marks or grid lines. - * - * @function - * @name pv.Scale.log.prototype.ticks - * @returns {number[]} an array input domain values to use as ticks. - */ - scale.ticks = function() { - // TODO: support multiple domains - var start = Math.floor(l[0]), - end = Math.ceil(l[1]), - ticks = []; - for (var i = start; i < end; i++) { - var x = Math.pow(b, i); - if (d[0] < 0) x = -x; - for (var j = 1; j < b; j++) { - ticks.push(x * j); - } - } - ticks.push(Math.pow(b, end)); - if (ticks[0] < d[0]) ticks.shift(); - if (ticks[ticks.length - 1] > d[1]) ticks.pop(); - return ticks; - }; - - /** - * Formats the specified tick value using the appropriate precision, assuming - * base 10. - * - * @function - * @name pv.Scale.log.prototype.tickFormat - * @param {number} t a tick value. - * @return {string} a formatted tick value. - */ - scale.tickFormat = function(t) { - return t.toPrecision(1); - }; - - /** - * "Nices" this scale, extending the bounds of the input domain to - * evenly-rounded values. This method uses {@link pv.logFloor} and {@link - * pv.logCeil}. Nicing is useful if the domain is computed dynamically from - * data, and may be irregular. For example, given a domain of - * [0.20147987687960267, 0.996679553296417], a call to <tt>nice()</tt> might - * extend the domain to [0.1, 1]. - * - * <p>This method must be invoked each time after setting the domain (and - * base). - * - * @function - * @name pv.Scale.log.prototype.nice - * @returns {pv.Scale.log} <tt>this</tt>. - */ - scale.nice = function() { - // TODO: support multiple domains - d = [pv.logFloor(d[0], b), pv.logCeil(d[1], b)]; - l = d.map(log); - return this; - }; - - /** - * Sets or gets the logarithm base. Defaults to 10. - * - * @function - * @name pv.Scale.log.prototype.base - * @param {number} [v] the new base. - * @returns {pv.Scale.log} <tt>this</tt>, or the current base. - */ - scale.base = function(v) { - if (arguments.length) { - b = v; - l = d.map(log); - return this; - } - return b; - }; - - /** - * Returns a view of this scale by the specified accessor function <tt>f</tt>. - * Given a scale <tt>y</tt>, <tt>y.by(function(d) d.foo)</tt> is equivalent to - * <tt>function(d) y(d.foo)</tt>. - * - * <p>This method is provided for convenience, such that scales can be - * succinctly defined inline. For example, given an array of data elements - * that have a <tt>score</tt> attribute with the domain [0, 1], the height - * property could be specified as: - * - * <pre>.height(pv.Scale.log().range(0, 480).by(function(d) d.score))</pre> - * - * This is equivalent to: - * - * <pre>.height(function(d) d.score * 480)</pre> - * - * This method should be used judiciously; it is typically more clear to - * invoke the scale directly, passing in the value to be scaled. - * - * @function - * @name pv.Scale.log.prototype.by - * @param {function} f an accessor function. - * @returns {pv.Scale.log} a view of this scale by the specified accessor - * function. - */ - scale.by = function(f) { - function by() { return scale(f.apply(this, arguments)); } - for (var method in scale) by[method] = scale[method]; - return by; - }; - - scale.domain.apply(scale, arguments); - return scale; -}; -/** - * Returns an ordinal scale for the specified domain. The arguments to this - * constructor are optional, and equivalent to calling {@link #domain}. - * - * @class Represents an ordinal scale. <style - * type="text/css">sub{line-height:0}</style> An ordinal scale represents a - * pairwise mapping from <i>n</i> discrete values in the input domain to - * <i>n</i> discrete values in the output range. For example, an ordinal scale - * might map a domain of species ["setosa", "versicolor", "virginica"] to colors - * ["red", "green", "blue"]. Thus, saying - * - * <pre>.fillStyle(function(d) { - * switch (d.species) { - * case "setosa": return "red"; - * case "versicolor": return "green"; - * case "virginica": return "blue"; - * } - * })</pre> - * - * is equivalent to - * - * <pre>.fillStyle(pv.Scale.ordinal("setosa", "versicolor", "virginica") - * .range("red", "green", "blue") - * .by(function(d) d.species))</pre> - * - * If the mapping from species to color does not need to be specified - * explicitly, the domain can be omitted. In this case it will be inferred - * lazily from the data: - * - * <pre>.fillStyle(pv.colors("red", "green", "blue") - * .by(function(d) d.species))</pre> - * - * When the domain is inferred, the first time the scale is invoked, the first - * element from the range will be returned. Subsequent calls with unique values - * will return subsequent elements from the range. If the inferred domain grows - * larger than the range, range values will be reused. However, it is strongly - * recommended that the domain and the range contain the same number of - * elements. - * - * <p>A range can be discretized from a continuous interval (e.g., for pixel - * positioning) by using {@link #split}, {@link #splitFlush} or - * {@link #splitBanded} after the domain has been set. For example, if - * <tt>states</tt> is an array of the fifty U.S. state names, the state name can - * be encoded in the left position: - * - * <pre>.left(pv.Scale.ordinal(states) - * .split(0, 640) - * .by(function(d) d.state))</pre> - * - * <p>N.B.: ordinal scales are not invertible (at least not yet), since the - * domain and range and discontinuous. A workaround is to use a linear scale. - * - * @param {...} domain... domain values. - * @returns {pv.Scale.ordinal} an ordinal scale. - * @see pv.colors - */ -pv.Scale.ordinal = function() { - var d = [], i = {}, r = [], band = 0; - - /** @private */ - function scale(x) { - if (!(x in i)) i[x] = d.push(x) - 1; - return r[i[x] % r.length]; - } - - /** - * Sets or gets the input domain. This method can be invoked several ways: - * - * <p>1. <tt>domain(values...)</tt> - * - * <p>Specifying the domain as a series of values is the most explicit and - * recommended approach. However, if the domain values are derived from data, - * you may find the second method more appropriate. - * - * <p>2. <tt>domain(array, f)</tt> - * - * <p>Rather than enumerating the domain values as explicit arguments to this - * method, you can specify a single argument of an array. In addition, you can - * specify an optional accessor function to extract the domain values from the - * array. - * - * <p>3. <tt>domain()</tt> - * - * <p>Invoking the <tt>domain</tt> method with no arguments returns the - * current domain as an array. - * - * @function - * @name pv.Scale.ordinal.prototype.domain - * @param {...} domain... domain values. - * @returns {pv.Scale.ordinal} <tt>this</tt>, or the current domain. - */ - scale.domain = function(array, f) { - if (arguments.length) { - array = (array instanceof Array) - ? ((arguments.length > 1) ? map(array, f) : array) - : Array.prototype.slice.call(arguments); - - /* Filter the specified ordinals to their unique values. */ - d = []; - var seen = {}; - for (var j = 0; j < array.length; j++) { - var o = array[j]; - if (!(o in seen)) { - seen[o] = true; - d.push(o); - } - } - - i = pv.numerate(d); - return this; - } - return d; - }; - - /** - * Sets or gets the output range. This method can be invoked several ways: - * - * <p>1. <tt>range(values...)</tt> - * - * <p>Specifying the range as a series of values is the most explicit and - * recommended approach. However, if the range values are derived from data, - * you may find the second method more appropriate. - * - * <p>2. <tt>range(array, f)</tt> - * - * <p>Rather than enumerating the range values as explicit arguments to this - * method, you can specify a single argument of an array. In addition, you can - * specify an optional accessor function to extract the range values from the - * array. - * - * <p>3. <tt>range()</tt> - * - * <p>Invoking the <tt>range</tt> method with no arguments returns the - * current range as an array. - * - * @function - * @name pv.Scale.ordinal.prototype.range - * @param {...} range... range values. - * @returns {pv.Scale.ordinal} <tt>this</tt>, or the current range. - */ - scale.range = function(array, f) { - if (arguments.length) { - r = (array instanceof Array) - ? ((arguments.length > 1) ? map(array, f) : array) - : Array.prototype.slice.call(arguments); - if (typeof r[0] == "string") r = r.map(pv.color); - return this; - } - return r; - }; - - /** - * Sets the range from the given continuous interval. The interval - * [<i>min</i>, <i>max</i>] is subdivided into <i>n</i> equispaced points, - * where <i>n</i> is the number of (unique) values in the domain. The first - * and last point are offset from the edge of the range by half the distance - * between points. - * - * <p>This method must be called <i>after</i> the domain is set. - * - * @function - * @name pv.Scale.ordinal.prototype.split - * @param {number} min minimum value of the output range. - * @param {number} max maximum value of the output range. - * @returns {pv.Scale.ordinal} <tt>this</tt>. - * @see #splitFlush - * @see #splitBanded - */ - scale.split = function(min, max) { - var step = (max - min) / this.domain().length; - r = pv.range(min + step / 2, max, step); - return this; - }; - - /** - * Sets the range from the given continuous interval. The interval - * [<i>min</i>, <i>max</i>] is subdivided into <i>n</i> equispaced points, - * where <i>n</i> is the number of (unique) values in the domain. The first - * and last point are exactly on the edge of the range. - * - * <p>This method must be called <i>after</i> the domain is set. - * - * @function - * @name pv.Scale.ordinal.prototype.splitFlush - * @param {number} min minimum value of the output range. - * @param {number} max maximum value of the output range. - * @returns {pv.Scale.ordinal} <tt>this</tt>. - * @see #split - */ - scale.splitFlush = function(min, max) { - var n = this.domain().length, step = (max - min) / (n - 1); - r = (n == 1) ? [(min + max) / 2] - : pv.range(min, max + step / 2, step); - return this; - }; - - /** - * Sets the range from the given continuous interval. The interval - * [<i>min</i>, <i>max</i>] is subdivided into <i>n</i> equispaced bands, - * where <i>n</i> is the number of (unique) values in the domain. The first - * and last band are offset from the edge of the range by the distance between - * bands. - * - * <p>The band width argument, <tt>band</tt>, is typically in the range [0, 1] - * and defaults to 1. This fraction corresponds to the amount of space in the - * range to allocate to the bands, as opposed to padding. A value of 0.5 means - * that the band width will be equal to the padding width. The computed - * absolute band width can be retrieved from the range as - * <tt>scale.range().band</tt>. - * - * <p>If the band width argument is negative, this method will allocate bands - * of a <i>fixed</i> width <tt>-band</tt>, rather than a relative fraction of - * the available space. - * - * <p>Tip: to inset the bands by a fixed amount <tt>p</tt>, specify a minimum - * value of <tt>min + p</tt> (or simply <tt>p</tt>, if <tt>min</tt> is - * 0). Then set the mark width to <tt>scale.range().band - p</tt>. - * - * <p>This method must be called <i>after</i> the domain is set. - * - * @function - * @name pv.Scale.ordinal.prototype.splitBanded - * @param {number} min minimum value of the output range. - * @param {number} max maximum value of the output range. - * @param {number} [band] the fractional band width in [0, 1]; defaults to 1. - * @returns {pv.Scale.ordinal} <tt>this</tt>. - * @see #split - */ - scale.splitBanded = function(min, max, band) { - if (arguments.length < 3) band = 1; - if (band < 0) { - var n = this.domain().length, - total = -band * n, - remaining = max - min - total, - padding = remaining / (n + 1); - r = pv.range(min + padding, max, padding - band); - r.band = -band; - } else { - var step = (max - min) / (this.domain().length + (1 - band)); - r = pv.range(min + step * (1 - band), max, step); - r.band = step * band; - } - return this; - }; - - /** - * Returns a view of this scale by the specified accessor function <tt>f</tt>. - * Given a scale <tt>y</tt>, <tt>y.by(function(d) d.foo)</tt> is equivalent to - * <tt>function(d) y(d.foo)</tt>. This method should be used judiciously; it - * is typically more clear to invoke the scale directly, passing in the value - * to be scaled. - * - * @function - * @name pv.Scale.ordinal.prototype.by - * @param {function} f an accessor function. - * @returns {pv.Scale.ordinal} a view of this scale by the specified accessor - * function. - */ - scale.by = function(f) { - function by() { return scale(f.apply(this, arguments)); } - for (var method in scale) by[method] = scale[method]; - return by; - }; - - scale.domain.apply(scale, arguments); - return scale; -}; -/** - * Returns the {@link pv.Color} for the specified color format string. Colors - * may have an associated opacity, or alpha channel. Color formats are specified - * by CSS Color Modular Level 3, using either in RGB or HSL color space. For - * example:<ul> - * - * <li>#f00 // #rgb - * <li>#ff0000 // #rrggbb - * <li>rgb(255, 0, 0) - * <li>rgb(100%, 0%, 0%) - * <li>hsl(0, 100%, 50%) - * <li>rgba(0, 0, 255, 0.5) - * <li>hsla(120, 100%, 50%, 1) - * - * </ul>The SVG 1.0 color keywords names are also supported, such as "aliceblue" - * and "yellowgreen". The "transparent" keyword is supported for a - * fully-transparent color. - * - * <p>If the <tt>format</tt> argument is already an instance of <tt>Color</tt>, - * the argument is returned with no further processing. - * - * @param {string} format the color specification string, such as "#f00". - * @returns {pv.Color} the corresponding <tt>Color</tt>. - * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">SVG color - * keywords</a> - * @see <a href="http://www.w3.org/TR/css3-color/">CSS3 color module</a> - */ -pv.color = function(format) { - if (!format || (format == "transparent")) { - return pv.rgb(0, 0, 0, 0); - } - if (format instanceof pv.Color) { - return format; - } - - /* Handle hsl, rgb. */ - var m1 = /([a-z]+)\((.*)\)/i.exec(format); - if (m1) { - var m2 = m1[2].split(","), a = 1; - switch (m1[1]) { - case "hsla": - case "rgba": { - a = parseFloat(m2[3]); - break; - } - } - switch (m1[1]) { - case "hsla": - case "hsl": { - var h = parseFloat(m2[0]), // degrees - s = parseFloat(m2[1]) / 100, // percentage - l = parseFloat(m2[2]) / 100; // percentage - return (new pv.Color.Hsl(h, s, l, a)).rgb(); - } - case "rgba": - case "rgb": { - function parse(c) { // either integer or percentage - var f = parseFloat(c); - return (c[c.length - 1] == '%') ? Math.round(f * 2.55) : f; - } - var r = parse(m2[0]), g = parse(m2[1]), b = parse(m2[2]); - return pv.rgb(r, g, b, a); - } - } - } - - /* Named colors. */ - format = pv.Color.names[format] || format; - - /* Hexadecimal colors: #rgb and #rrggbb. */ - if (format.charAt(0) == "#") { - var r, g, b; - if (format.length == 4) { - r = format.charAt(1); r += r; - g = format.charAt(2); g += g; - b = format.charAt(3); b += b; - } else if (format.length == 7) { - r = format.substring(1, 3); - g = format.substring(3, 5); - b = format.substring(5, 7); - } - return pv.rgb(parseInt(r, 16), parseInt(g, 16), parseInt(b, 16), 1); - } - - /* Otherwise, assume named colors. TODO allow lazy conversion to RGB. */ - return new pv.Color(format, 1); -}; - -/** - * Constructs a color with the specified color format string and opacity. This - * constructor should not be invoked directly; use {@link pv.color} instead. - * - * @class Represents an abstract (possibly translucent) color. The color is - * divided into two parts: the <tt>color</tt> attribute, an opaque color format - * string, and the <tt>opacity</tt> attribute, a float in [0, 1]. The color - * space is dependent on the implementing class; all colors support the - * {@link #rgb} method to convert to RGB color space for interpolation. - * - * <p>See also the <a href="../../api/Color.html">Color guide</a>. - * - * @param {string} color an opaque color format string, such as "#f00". - * @param {number} opacity the opacity, in [0,1]. - * @see pv.color - */ -pv.Color = function(color, opacity) { - /** - * An opaque color format string, such as "#f00". - * - * @type string - * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">SVG color - * keywords</a> - * @see <a href="http://www.w3.org/TR/css3-color/">CSS3 color module</a> - */ - this.color = color; - - /** - * The opacity, a float in [0, 1]. - * - * @type number - */ - this.opacity = opacity; -}; - -/** - * Returns a new color that is a brighter version of this color. The behavior of - * this method may vary slightly depending on the underlying color space. - * Although brighter and darker are inverse operations, the results of a series - * of invocations of these two methods might be inconsistent because of rounding - * errors. - * - * @param [k] {number} an optional scale factor; defaults to 1. - * @see #darker - * @returns {pv.Color} a brighter color. - */ -pv.Color.prototype.brighter = function(k) { - return this.rgb().brighter(k); -}; - -/** - * Returns a new color that is a brighter version of this color. The behavior of - * this method may vary slightly depending on the underlying color space. - * Although brighter and darker are inverse operations, the results of a series - * of invocations of these two methods might be inconsistent because of rounding - * errors. - * - * @param [k] {number} an optional scale factor; defaults to 1. - * @see #brighter - * @returns {pv.Color} a darker color. - */ -pv.Color.prototype.darker = function(k) { - return this.rgb().darker(k); -}; - -/** - * Constructs a new RGB color with the specified channel values. - * - * @param {number} r the red channel, an integer in [0,255]. - * @param {number} g the green channel, an integer in [0,255]. - * @param {number} b the blue channel, an integer in [0,255]. - * @param {number} [a] the alpha channel, a float in [0,1]. - * @returns pv.Color.Rgb - */ -pv.rgb = function(r, g, b, a) { - return new pv.Color.Rgb(r, g, b, (arguments.length == 4) ? a : 1); -}; - -/** - * Constructs a new RGB color with the specified channel values. - * - * @class Represents a color in RGB space. - * - * @param {number} r the red channel, an integer in [0,255]. - * @param {number} g the green channel, an integer in [0,255]. - * @param {number} b the blue channel, an integer in [0,255]. - * @param {number} a the alpha channel, a float in [0,1]. - * @extends pv.Color - */ -pv.Color.Rgb = function(r, g, b, a) { - pv.Color.call(this, a ? ("rgb(" + r + "," + g + "," + b + ")") : "none", a); - - /** - * The red channel, an integer in [0, 255]. - * - * @type number - */ - this.r = r; - - /** - * The green channel, an integer in [0, 255]. - * - * @type number - */ - this.g = g; - - /** - * The blue channel, an integer in [0, 255]. - * - * @type number - */ - this.b = b; - - /** - * The alpha channel, a float in [0, 1]. - * - * @type number - */ - this.a = a; -}; -pv.Color.Rgb.prototype = pv.extend(pv.Color); - -/** - * Constructs a new RGB color with the same green, blue and alpha channels as - * this color, with the specified red channel. - * - * @param {number} r the red channel, an integer in [0,255]. - */ -pv.Color.Rgb.prototype.red = function(r) { - return pv.rgb(r, this.g, this.b, this.a); -}; - -/** - * Constructs a new RGB color with the same red, blue and alpha channels as this - * color, with the specified green channel. - * - * @param {number} g the green channel, an integer in [0,255]. - */ -pv.Color.Rgb.prototype.green = function(g) { - return pv.rgb(this.r, g, this.b, this.a); -}; - -/** - * Constructs a new RGB color with the same red, green and alpha channels as - * this color, with the specified blue channel. - * - * @param {number} b the blue channel, an integer in [0,255]. - */ -pv.Color.Rgb.prototype.blue = function(b) { - return pv.rgb(this.r, this.g, b, this.a); -}; - -/** - * Constructs a new RGB color with the same red, green and blue channels as this - * color, with the specified alpha channel. - * - * @param {number} a the alpha channel, a float in [0,1]. - */ -pv.Color.Rgb.prototype.alpha = function(a) { - return pv.rgb(this.r, this.g, this.b, a); -}; - -/** - * Returns the RGB color equivalent to this color. This method is abstract and - * must be implemented by subclasses. - * - * @returns {pv.Color.Rgb} an RGB color. - * @function - * @name pv.Color.prototype.rgb - */ - -/** - * Returns this. - * - * @returns {pv.Color.Rgb} this. - */ -pv.Color.Rgb.prototype.rgb = function() { return this; }; - -/** - * Returns a new color that is a brighter version of this color. This method - * applies an arbitrary scale factor to each of the three RGB components of this - * color to create a brighter version of this color. Although brighter and - * darker are inverse operations, the results of a series of invocations of - * these two methods might be inconsistent because of rounding errors. - * - * @param [k] {number} an optional scale factor; defaults to 1. - * @see #darker - * @returns {pv.Color.Rgb} a brighter color. - */ -pv.Color.Rgb.prototype.brighter = function(k) { - k = Math.pow(0.7, arguments.length ? k : 1); - var r = this.r, g = this.g, b = this.b, i = 30; - if (!r && !g && !b) return pv.rgb(i, i, i, this.a); - if (r && (r < i)) r = i; - if (g && (g < i)) g = i; - if (b && (b < i)) b = i; - return pv.rgb( - Math.min(255, Math.floor(r / k)), - Math.min(255, Math.floor(g / k)), - Math.min(255, Math.floor(b / k)), - this.a); -}; - -/** - * Returns a new color that is a darker version of this color. This method - * applies an arbitrary scale factor to each of the three RGB components of this - * color to create a darker version of this color. Although brighter and darker - * are inverse operations, the results of a series of invocations of these two - * methods might be inconsistent because of rounding errors. - * - * @param [k] {number} an optional scale factor; defaults to 1. - * @see #brighter - * @returns {pv.Color.Rgb} a darker color. - */ -pv.Color.Rgb.prototype.darker = function(k) { - k = Math.pow(0.7, arguments.length ? k : 1); - return pv.rgb( - Math.max(0, Math.floor(k * this.r)), - Math.max(0, Math.floor(k * this.g)), - Math.max(0, Math.floor(k * this.b)), - this.a); -}; - -/** - * Constructs a new HSL color with the specified values. - * - * @param {number} h the hue, an integer in [0, 360]. - * @param {number} s the saturation, a float in [0, 1]. - * @param {number} l the lightness, a float in [0, 1]. - * @param {number} [a] the opacity, a float in [0, 1]. - * @returns pv.Color.Hsl - */ -pv.hsl = function(h, s, l, a) { - return new pv.Color.Hsl(h, s, l, (arguments.length == 4) ? a : 1); -}; - -/** - * Constructs a new HSL color with the specified values. - * - * @class Represents a color in HSL space. - * - * @param {number} h the hue, an integer in [0, 360]. - * @param {number} s the saturation, a float in [0, 1]. - * @param {number} l the lightness, a float in [0, 1]. - * @param {number} a the opacity, a float in [0, 1]. - * @extends pv.Color - */ -pv.Color.Hsl = function(h, s, l, a) { - pv.Color.call(this, "hsl(" + h + "," + (s * 100) + "%," + (l * 100) + "%)", a); - - /** - * The hue, an integer in [0, 360]. - * - * @type number - */ - this.h = h; - - /** - * The saturation, a float in [0, 1]. - * - * @type number - */ - this.s = s; - - /** - * The lightness, a float in [0, 1]. - * - * @type number - */ - this.l = l; - - /** - * The opacity, a float in [0, 1]. - * - * @type number - */ - this.a = a; -}; -pv.Color.Hsl.prototype = pv.extend(pv.Color); - -/** - * Constructs a new HSL color with the same saturation, lightness and alpha as - * this color, and the specified hue. - * - * @param {number} h the hue, an integer in [0, 360]. - */ -pv.Color.Hsl.prototype.hue = function(h) { - return pv.hsl(h, this.s, this.l, this.a); -}; - -/** - * Constructs a new HSL color with the same hue, lightness and alpha as this - * color, and the specified saturation. - * - * @param {number} s the saturation, a float in [0, 1]. - */ -pv.Color.Hsl.prototype.saturation = function(s) { - return pv.hsl(this.h, s, this.l, this.a); -}; - -/** - * Constructs a new HSL color with the same hue, saturation and alpha as this - * color, and the specified lightness. - * - * @param {number} l the lightness, a float in [0, 1]. - */ -pv.Color.Hsl.prototype.lightness = function(l) { - return pv.hsl(this.h, this.s, l, this.a); -}; - -/** - * Constructs a new HSL color with the same hue, saturation and lightness as - * this color, and the specified alpha. - * - * @param {number} a the opacity, a float in [0, 1]. - */ -pv.Color.Hsl.prototype.alpha = function(a) { - return pv.hsl(this.h, this.s, this.l, a); -}; - -/** - * Returns the RGB color equivalent to this HSL color. - * - * @returns {pv.Color.Rgb} an RGB color. - */ -pv.Color.Hsl.prototype.rgb = function() { - var h = this.h, s = this.s, l = this.l; - - /* Some simple corrections for h, s and l. */ - h = h % 360; if (h < 0) h += 360; - s = Math.max(0, Math.min(s, 1)); - l = Math.max(0, Math.min(l, 1)); - - /* From FvD 13.37, CSS Color Module Level 3 */ - var m2 = (l <= .5) ? (l * (1 + s)) : (l + s - l * s); - var m1 = 2 * l - m2; - function v(h) { - if (h > 360) h -= 360; - else if (h < 0) h += 360; - if (h < 60) return m1 + (m2 - m1) * h / 60; - if (h < 180) return m2; - if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; - return m1; - } - function vv(h) { - return Math.round(v(h) * 255); - } - - return pv.rgb(vv(h + 120), vv(h), vv(h - 120), this.a); -}; - -/** - * @private SVG color keywords, per CSS Color Module Level 3. - * - * @see <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords">SVG color - * keywords</a> - */ -pv.Color.names = { - aliceblue: "#f0f8ff", - antiquewhite: "#faebd7", - aqua: "#00ffff", - aquamarine: "#7fffd4", - azure: "#f0ffff", - beige: "#f5f5dc", - bisque: "#ffe4c4", - black: "#000000", - blanchedalmond: "#ffebcd", - blue: "#0000ff", - blueviolet: "#8a2be2", - brown: "#a52a2a", - burlywood: "#deb887", - cadetblue: "#5f9ea0", - chartreuse: "#7fff00", - chocolate: "#d2691e", - coral: "#ff7f50", - cornflowerblue: "#6495ed", - cornsilk: "#fff8dc", - crimson: "#dc143c", - cyan: "#00ffff", - darkblue: "#00008b", - darkcyan: "#008b8b", - darkgoldenrod: "#b8860b", - darkgray: "#a9a9a9", - darkgreen: "#006400", - darkgrey: "#a9a9a9", - darkkhaki: "#bdb76b", - darkmagenta: "#8b008b", - darkolivegreen: "#556b2f", - darkorange: "#ff8c00", - darkorchid: "#9932cc", - darkred: "#8b0000", - darksalmon: "#e9967a", - darkseagreen: "#8fbc8f", - darkslateblue: "#483d8b", - darkslategray: "#2f4f4f", - darkslategrey: "#2f4f4f", - darkturquoise: "#00ced1", - darkviolet: "#9400d3", - deeppink: "#ff1493", - deepskyblue: "#00bfff", - dimgray: "#696969", - dimgrey: "#696969", - dodgerblue: "#1e90ff", - firebrick: "#b22222", - floralwhite: "#fffaf0", - forestgreen: "#228b22", - fuchsia: "#ff00ff", - gainsboro: "#dcdcdc", - ghostwhite: "#f8f8ff", - gold: "#ffd700", - goldenrod: "#daa520", - gray: "#808080", - green: "#008000", - greenyellow: "#adff2f", - grey: "#808080", - honeydew: "#f0fff0", - hotpink: "#ff69b4", - indianred: "#cd5c5c", - indigo: "#4b0082", - ivory: "#fffff0", - khaki: "#f0e68c", - lavender: "#e6e6fa", - lavenderblush: "#fff0f5", - lawngreen: "#7cfc00", - lemonchiffon: "#fffacd", - lightblue: "#add8e6", - lightcoral: "#f08080", - lightcyan: "#e0ffff", - lightgoldenrodyellow: "#fafad2", - lightgray: "#d3d3d3", - lightgreen: "#90ee90", - lightgrey: "#d3d3d3", - lightpink: "#ffb6c1", - lightsalmon: "#ffa07a", - lightseagreen: "#20b2aa", - lightskyblue: "#87cefa", - lightslategray: "#778899", - lightslategrey: "#778899", - lightsteelblue: "#b0c4de", - lightyellow: "#ffffe0", - lime: "#00ff00", - limegreen: "#32cd32", - linen: "#faf0e6", - magenta: "#ff00ff", - maroon: "#800000", - mediumaquamarine: "#66cdaa", - mediumblue: "#0000cd", - mediumorchid: "#ba55d3", - mediumpurple: "#9370db", - mediumseagreen: "#3cb371", - mediumslateblue: "#7b68ee", - mediumspringgreen: "#00fa9a", - mediumturquoise: "#48d1cc", - mediumvioletred: "#c71585", - midnightblue: "#191970", - mintcream: "#f5fffa", - mistyrose: "#ffe4e1", - moccasin: "#ffe4b5", - navajowhite: "#ffdead", - navy: "#000080", - oldlace: "#fdf5e6", - olive: "#808000", - olivedrab: "#6b8e23", - orange: "#ffa500", - orangered: "#ff4500", - orchid: "#da70d6", - palegoldenrod: "#eee8aa", - palegreen: "#98fb98", - paleturquoise: "#afeeee", - palevioletred: "#db7093", - papayawhip: "#ffefd5", - peachpuff: "#ffdab9", - peru: "#cd853f", - pink: "#ffc0cb", - plum: "#dda0dd", - powderblue: "#b0e0e6", - purple: "#800080", - red: "#ff0000", - rosybrown: "#bc8f8f", - royalblue: "#4169e1", - saddlebrown: "#8b4513", - salmon: "#fa8072", - sandybrown: "#f4a460", - seagreen: "#2e8b57", - seashell: "#fff5ee", - sienna: "#a0522d", - silver: "#c0c0c0", - skyblue: "#87ceeb", - slateblue: "#6a5acd", - slategray: "#708090", - slategrey: "#708090", - snow: "#fffafa", - springgreen: "#00ff7f", - steelblue: "#4682b4", - tan: "#d2b48c", - teal: "#008080", - thistle: "#d8bfd8", - tomato: "#ff6347", - turquoise: "#40e0d0", - violet: "#ee82ee", - wheat: "#f5deb3", - white: "#ffffff", - whitesmoke: "#f5f5f5", - yellow: "#ffff00", - yellowgreen: "#9acd32" -}; -/** - * Returns a new categorical color encoding using the specified colors. The - * arguments to this method are an array of colors; see {@link pv.color}. For - * example, to create a categorical color encoding using the <tt>species</tt> - * attribute: - * - * <pre>pv.colors("red", "green", "blue").by(function(d) d.species)</pre> - * - * The result of this expression can be used as a fill- or stroke-style - * property. This assumes that the data's <tt>species</tt> attribute is a - * string. - * - * @param {string} colors... categorical colors. - * @see pv.Scale.ordinal - * @returns {pv.Scale.ordinal} an ordinal color scale. - */ -pv.colors = function() { - var scale = pv.Scale.ordinal(); - scale.range.apply(scale, arguments); - return scale; -}; - -/** - * A collection of standard color palettes for categorical encoding. - * - * @namespace A collection of standard color palettes for categorical encoding. - */ -pv.Colors = {}; - -/** - * Returns a new 10-color scheme. The arguments to this constructor are - * optional, and equivalent to calling {@link pv.Scale.OrdinalScale#domain}. The - * following colors are used: - * - * <div style="background:#1f77b4;">#1f77b4</div> - * <div style="background:#ff7f0e;">#ff7f0e</div> - * <div style="background:#2ca02c;">#2ca02c</div> - * <div style="background:#d62728;">#d62728</div> - * <div style="background:#9467bd;">#9467bd</div> - * <div style="background:#8c564b;">#8c564b</div> - * <div style="background:#e377c2;">#e377c2</div> - * <div style="background:#7f7f7f;">#7f7f7f</div> - * <div style="background:#bcbd22;">#bcbd22</div> - * <div style="background:#17becf;">#17becf</div> - * - * @param {number...} domain... domain values. - * @returns {pv.Scale.ordinal} a new ordinal color scale. - * @see pv.color - */ -pv.Colors.category10 = function() { - var scale = pv.colors( - "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", - "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"); - scale.domain.apply(scale, arguments); - return scale; -}; - -/** - * Returns a new 20-color scheme. The arguments to this constructor are - * optional, and equivalent to calling {@link pv.Scale.OrdinalScale#domain}. The - * following colors are used: - * - * <div style="background:#1f77b4;">#1f77b4</div> - * <div style="background:#aec7e8;">#aec7e8</div> - * <div style="background:#ff7f0e;">#ff7f0e</div> - * <div style="background:#ffbb78;">#ffbb78</div> - * <div style="background:#2ca02c;">#2ca02c</div> - * <div style="background:#98df8a;">#98df8a</div> - * <div style="background:#d62728;">#d62728</div> - * <div style="background:#ff9896;">#ff9896</div> - * <div style="background:#9467bd;">#9467bd</div> - * <div style="background:#c5b0d5;">#c5b0d5</div> - * <div style="background:#8c564b;">#8c564b</div> - * <div style="background:#c49c94;">#c49c94</div> - * <div style="background:#e377c2;">#e377c2</div> - * <div style="background:#f7b6d2;">#f7b6d2</div> - * <div style="background:#7f7f7f;">#7f7f7f</div> - * <div style="background:#c7c7c7;">#c7c7c7</div> - * <div style="background:#bcbd22;">#bcbd22</div> - * <div style="background:#dbdb8d;">#dbdb8d</div> - * <div style="background:#17becf;">#17becf</div> - * <div style="background:#9edae5;">#9edae5</div> - * - * @param {number...} domain... domain values. - * @returns {pv.Scale.ordinal} a new ordinal color scale. - * @see pv.color -*/ -pv.Colors.category20 = function() { - var scale = pv.colors( - "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", - "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", - "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", - "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5"); - scale.domain.apply(scale, arguments); - return scale; -}; - -/** - * Returns a new alternative 19-color scheme. The arguments to this constructor - * are optional, and equivalent to calling - * {@link pv.Scale.OrdinalScale#domain}. The following colors are used: - * - * <div style="background:#9c9ede;">#9c9ede</div> - * <div style="background:#7375b5;">#7375b5</div> - * <div style="background:#4a5584;">#4a5584</div> - * <div style="background:#cedb9c;">#cedb9c</div> - * <div style="background:#b5cf6b;">#b5cf6b</div> - * <div style="background:#8ca252;">#8ca252</div> - * <div style="background:#637939;">#637939</div> - * <div style="background:#e7cb94;">#e7cb94</div> - * <div style="background:#e7ba52;">#e7ba52</div> - * <div style="background:#bd9e39;">#bd9e39</div> - * <div style="background:#8c6d31;">#8c6d31</div> - * <div style="background:#e7969c;">#e7969c</div> - * <div style="background:#d6616b;">#d6616b</div> - * <div style="background:#ad494a;">#ad494a</div> - * <div style="background:#843c39;">#843c39</div> - * <div style="background:#de9ed6;">#de9ed6</div> - * <div style="background:#ce6dbd;">#ce6dbd</div> - * <div style="background:#a55194;">#a55194</div> - * <div style="background:#7b4173;">#7b4173</div> - * - * @param {number...} domain... domain values. - * @returns {pv.Scale.ordinal} a new ordinal color scale. - * @see pv.color - */ -pv.Colors.category19 = function() { - var scale = pv.colors( - "#9c9ede", "#7375b5", "#4a5584", "#cedb9c", "#b5cf6b", - "#8ca252", "#637939", "#e7cb94", "#e7ba52", "#bd9e39", - "#8c6d31", "#e7969c", "#d6616b", "#ad494a", "#843c39", - "#de9ed6", "#ce6dbd", "#a55194", "#7b4173"); - scale.domain.apply(scale, arguments); - return scale; -}; -/** - * Returns a linear color ramp from the specified <tt>start</tt> color to the - * specified <tt>end</tt> color. The color arguments may be specified either as - * <tt>string</tt>s or as {@link pv.Color}s. - * - * @param {string} start the start color; may be a <tt>pv.Color</tt>. - * @param {string} end the end color; may be a <tt>pv.Color</tt>. - * @returns {Function} a color ramp from <tt>start</tt> to <tt>end</tt>. - * @see pv.Scale.linear - */ -pv.ramp = function(start, end) { - var scale = pv.Scale.linear(); - scale.range.apply(scale, arguments); - return scale; -}; -// TODO don't populate default attributes? - -/** - * @private - * @namespace - */ -pv.Scene = pv.SvgScene = {}; - -/** - * Updates the display for the specified array of scene nodes. - * - * @param scenes {array} an array of scene nodes. - */ -pv.SvgScene.updateAll = function(scenes) { - if (!scenes.length) return; - if ((scenes[0].reverse) - && (scenes.type != "line") - && (scenes.type != "area")) { - var reversed = pv.extend(scenes); - for (var i = 0, j = scenes.length - 1; j >= 0; i++, j--) { - reversed[i] = scenes[j]; - } - scenes = reversed; - } - this.removeSiblings(this[scenes.type](scenes)); -}; - -/** - * Creates a new SVG element of the specified type. - * - * @param type {string} an SVG element type, such as "rect". - * @return a new SVG element. - */ -pv.SvgScene.create = function(type) { - return document.createElementNS(pv.ns.svg, type); -}; - -/** - * Expects the element <i>e</i> to be the specified type. If the element does - * not exist, a new one is created. If the element does exist but is the wrong - * type, it is replaced with the specified element. - * - * @param type {string} an SVG element type, such as "rect". - * @return a new SVG element. - */ -pv.SvgScene.expect = function(type, e) { - if (!e) return this.create(type); - if (e.tagName == "a") e = e.firstChild; - if (e.tagName == type) return e; - var n = this.create(type); - e.parentNode.replaceChild(n, e); - return n; -}; - -/** TODO */ -pv.SvgScene.append = function(e, scenes, index) { - e.$scene = {scenes:scenes, index:index}; - e = this.title(e, scenes[index]); - if (!e.parentNode) scenes.$g.appendChild(e); - return e.nextSibling; -}; - -/** - * Applies a title tooltip to the specified element <tt>e</tt>, using the - * <tt>title</tt> property of the specified scene node <tt>s</tt>. Note that - * this implementation does not create an SVG <tt>title</tt> element as a child - * of <tt>e</tt>; although this is the recommended standard, it is only - * supported in Opera. Instead, an anchor element is created around the element - * <tt>e</tt>, and the <tt>xlink:title</tt> attribute is set accordingly. - * - * @param e an SVG element. - * @param s a scene node. - */ -pv.SvgScene.title = function(e, s) { - var a = e.parentNode, t = String(s.title); - if (a && (a.tagName != "a")) a = null; - if (t) { - if (!a) { - a = this.create("a"); - if (e.parentNode) e.parentNode.replaceChild(a, e); - a.appendChild(e); - } - a.setAttributeNS(pv.ns.xlink, "title", t); - return a; - } - if (a) a.parentNode.replaceChild(e, a); - return e; -}; - -/** TODO */ -pv.SvgScene.dispatch = function(e) { - var t = e.target.$scene; - if (t) { - t.scenes.mark.dispatch(e.type, t.scenes, t.index); - e.preventDefault(); - } -}; - -/** TODO */ -pv.SvgScene.removeSiblings = function(e) { - while (e) { - var n = e.nextSibling; - e.parentNode.removeChild(e); - e = n; - } -}; -// TODO strokeStyle for areaSegment? - -pv.SvgScene.area = function(scenes) { - var e = scenes.$g.firstChild; - if (!scenes.length) return e; - var s = scenes[0]; - - /* segmented */ - if (s.segmented) return this.areaSegment(scenes); - - /* visible */ - if (!s.visible) return e; - var fill = pv.color(s.fillStyle), stroke = pv.color(s.strokeStyle); - if (!fill.opacity && !stroke.opacity) return e; - - /* points */ - var p1 = "", p2 = ""; - for (var i = 0, j = scenes.length - 1; j >= 0; i++, j--) { - var si = scenes[i], sj = scenes[j]; - p1 += si.left + "," + si.top + " "; - p2 += (sj.left + sj.width) + "," + (sj.top + sj.height) + " "; - - /* interpolate (assume linear by default) */ - if (i < scenes.length - 1) { - var sk = scenes[i + 1], sl = scenes[j - 1]; - switch (s.interpolate) { - case "step-before": { - p1 += si.left + "," + sk.top + " "; - p2 += (sl.left + sl.width) + "," + (sj.top + sj.height) + " "; - break; - } - case "step-after": { - p1 += sk.left + "," + si.top + " "; - p2 += (sj.left + sj.width) + "," + (sl.top + sl.height) + " "; - break; - } - } - } - } - - e = this.expect("polygon", e); - e.setAttribute("cursor", s.cursor); - e.setAttribute("points", p1 + p2); - var fill = pv.color(s.fillStyle); - e.setAttribute("fill", fill.color); - e.setAttribute("fill-opacity", fill.opacity); - var stroke = pv.color(s.strokeStyle); - e.setAttribute("stroke", stroke.color); - e.setAttribute("stroke-opacity", stroke.opacity); - e.setAttribute("stroke-width", s.lineWidth); - return this.append(e, scenes, 0); -}; - -pv.SvgScene.areaSegment = function(scenes) { - var e = scenes.$g.firstChild; - for (var i = 0, n = scenes.length - 1; i < n; i++) { - var s1 = scenes[i], s2 = scenes[i + 1]; - - /* visible */ - if (!s1.visible || !s2.visible) continue; - var fill = pv.color(s1.fillStyle), stroke = pv.color(s1.strokeStyle); - if (!fill.opacity && !stroke.opacity) continue; - - /* points */ - var p = s1.left + "," + s1.top + " " - + s2.left + "," + s2.top + " " - + (s2.left + s2.width) + "," + (s2.top + s2.height) + " " - + (s1.left + s1.width) + "," + (s1.top + s1.height); - - e = this.expect("polygon", e); - e.setAttribute("cursor", s1.cursor); - e.setAttribute("points", p); - e.setAttribute("fill", fill.color); - e.setAttribute("fill-opacity", fill.opacity); - e.setAttribute("stroke", stroke.color); - e.setAttribute("stroke-opacity", stroke.opacity); - e.setAttribute("stroke-width", s1.lineWidth); - e = this.append(e, scenes, i); - } - return e; -}; -pv.SvgScene.bar = function(scenes) { - var e = scenes.$g.firstChild; - for (var i = 0; i < scenes.length; i++) { - var s = scenes[i]; - - /* visible */ - if (!s.visible) continue; - var fill = pv.color(s.fillStyle), stroke = pv.color(s.strokeStyle); - if (!fill.opacity && !stroke.opacity) continue; - - e = this.expect("rect", e); - e.setAttribute("cursor", s.cursor); - e.setAttribute("x", s.left); - e.setAttribute("y", s.top); - e.setAttribute("width", Math.max(1E-10, s.width)); - e.setAttribute("height", Math.max(1E-10, s.height)); - e.setAttribute("fill", fill.color); - e.setAttribute("fill-opacity", fill.opacity); - e.setAttribute("stroke", stroke.color); - e.setAttribute("stroke-opacity", stroke.opacity); - e.setAttribute("stroke-width", s.lineWidth); - e = this.append(e, scenes, i); - } - return e; -}; -pv.SvgScene.dot = function(scenes) { - var e = scenes.$g.firstChild; - for (var i = 0; i < scenes.length; i++) { - var s = scenes[i]; - - /* visible */ - if (!s.visible) continue; - var fill = pv.color(s.fillStyle), stroke = pv.color(s.strokeStyle); - if (!fill.opacity && !stroke.opacity) continue; - - /* points */ - var radius = Math.sqrt(s.size), fillPath = "", strokePath = ""; - switch (s.shape) { - case "cross": { - fillPath = "M" + -radius + "," + -radius - + "L" + radius + "," + radius - + "M" + radius + "," + -radius - + "L" + -radius + "," + radius; - break; - } - case "triangle": { - var h = radius, w = radius * 2 / Math.sqrt(3); - fillPath = "M0," + h - + "L" + w +"," + -h - + " " + -w + "," + -h - + "Z"; - break; - } - case "diamond": { - radius *= Math.sqrt(2); - fillPath = "M0," + -radius - + "L" + radius + ",0" - + " 0," + radius - + " " + -radius + ",0" - + "Z"; - break; - } - case "square": { - fillPath = "M" + -radius + "," + -radius - + "L" + radius + "," + -radius - + " " + radius + "," + radius - + " " + -radius + "," + radius - + "Z"; - break; - } - case "tick": { - fillPath = "M0,0L0," + -s.size; - break; - } - default: { - function circle(r) { - return "M0," + r - + "A" + r + "," + r + " 0 1,1 0," + (-r) - + "A" + r + "," + r + " 0 1,1 0," + r - + "Z"; - } - if (s.lineWidth / 2 > radius) strokePath = circle(s.lineWidth); - fillPath = circle(radius); - break; - } - } - - /* transform */ - var transform = "translate(" + s.left + "," + s.top + ")" - + (s.angle ? " rotate(" + 180 * s.angle / Math.PI + ")" : ""); - - /* The normal fill path. */ - e = this.expect("path", e); - e.setAttribute("d", fillPath); - e.setAttribute("transform", transform); - e.setAttribute("fill", fill.color); - e.setAttribute("fill-opacity", fill.opacity); - e.setAttribute("cursor", s.cursor); - if (strokePath) { - e.setAttribute("stroke", "none"); - } else { - e.setAttribute("stroke", stroke.color); - e.setAttribute("stroke-opacity", stroke.opacity); - e.setAttribute("stroke-width", s.lineWidth); - } - e = this.append(e, scenes, i); - - /* The special-case stroke path. */ - if (strokePath) { - e = this.expect("path", e); - e.setAttribute("d", strokePath); - e.setAttribute("transform", transform); - e.setAttribute("fill", stroke.color); - e.setAttribute("fill-opacity", stroke.opacity); - e.setAttribute("cursor", s.cursor); - e = this.append(e, scenes, i); - } - } - return e; -}; -pv.SvgScene.image = function(scenes) { - var e = scenes.$g.firstChild; - for (var i = 0; i < scenes.length; i++) { - var s = scenes[i]; - - /* visible */ - if (!s.visible) continue; - - /* fill */ - e = this.fill(e, scenes, i); - - /* image */ - e = this.expect("image", e); - e.setAttribute("preserveAspectRatio", "none"); - e.setAttribute("x", s.left); - e.setAttribute("y", s.top); - e.setAttribute("width", s.width); - e.setAttribute("height", s.height); - e.setAttribute("cursor", s.cursor); - e.setAttributeNS(pv.ns.xlink, "href", s.url); - e = this.append(e, scenes, i); - - /* stroke */ - e = this.stroke(e, scenes, i); - } - return e; -}; -pv.SvgScene.label = function(scenes) { - var e = scenes.$g.firstChild; - for (var i = 0; i < scenes.length; i++) { - var s = scenes[i]; - - /* visible */ - if (!s.visible) continue; - var fill = pv.color(s.textStyle); - if (!fill.opacity) continue; - - /* text-baseline, text-align */ - var x = 0, y = 0, dy = 0, anchor = "start"; - switch (s.textBaseline) { - case "middle": dy = ".35em"; break; - case "top": dy = ".71em"; y = s.textMargin; break; - case "bottom": y = "-" + s.textMargin; break; - } - switch (s.textAlign) { - case "right": anchor = "end"; x = "-" + s.textMargin; break; - case "center": anchor = "middle"; break; - case "left": x = s.textMargin; break; - } - - e = this.expect("text", e); - e.setAttribute("pointer-events", "none"); - e.setAttribute("x", x); - e.setAttribute("y", y); - e.setAttribute("dy", dy); - e.setAttribute("text-anchor", anchor); - e.setAttribute("transform", - "translate(" + s.left + "," + s.top + ")" - + (s.textAngle ? " rotate(" + 180 * s.textAngle / Math.PI + ")" : "")); - e.setAttribute("fill", fill.color); - e.setAttribute("fill-opacity", fill.opacity); - e.style.font = s.font; - e.style.textShadow = s.textShadow; - if (e.firstChild) e.firstChild.nodeValue = s.text; - else e.appendChild(document.createTextNode(s.text)); - e = this.append(e, scenes, i); - } - return e; -}; -// TODO fillStyle for lineSegment? -// TODO lineOffset for flow maps? - -pv.SvgScene.line = function(scenes) { - var e = scenes.$g.firstChild; - if (scenes.length < 2) return e; - var s = scenes[0]; - - /* segmented */ - if (s.segmented) return this.lineSegment(scenes); - - /* visible */ - if (!s.visible) return e; - var fill = pv.color(s.fillStyle), stroke = pv.color(s.strokeStyle); - if (!fill.opacity && !stroke.opacity) return e; - - /* points */ - var p = ""; - for (var i = 0; i < scenes.length; i++) { - var si = scenes[i]; - p += si.left + "," + si.top + " "; - - /* interpolate (assume linear by default) */ - if (i < scenes.length - 1) { - var sj = scenes[i + 1]; - switch (s.interpolate) { - case "step-before": { - p += si.left + "," + sj.top + " "; - break; - } - case "step-after": { - p += sj.left + "," + si.top + " "; - break; - } - } - } - } - - - e = this.expect("polyline", e); - e.setAttribute("cursor", s.cursor); - e.setAttribute("points", p); - e.setAttribute("fill", fill.color); - e.setAttribute("fill-opacity", fill.opacity); - e.setAttribute("stroke", stroke.color); - e.setAttribute("stroke-opacity", stroke.opacity); - e.setAttribute("stroke-width", s.lineWidth); - return this.append(e, scenes, 0); -}; - -pv.SvgScene.lineSegment = function(scenes) { - var e = scenes.$g.firstChild; - for (var i = 0, n = scenes.length - 1; i < n; i++) { - var s1 = scenes[i], s2 = scenes[i + 1]; - - /* visible */ - if (!s1.visible || !s2.visible) continue; - var stroke = pv.color(s1.strokeStyle); - if (!stroke.opacity) continue; - - /* Line-line intersection, per Akenine-Moller 16.16.1. */ - function intersect(o1, d1, o2, d2) { - return o1.plus(d1.times(o2.minus(o1).dot(d2.perp()) / d1.dot(d2.perp()))); - } - - /* - * P1-P2 is the current line segment. V is a vector that is perpendicular to - * the line segment, and has length lineWidth / 2. ABCD forms the initial - * bounding box of the line segment (i.e., the line segment if we were to do - * no joins). - */ - var p1 = pv.vector(s1.left, s1.top), - p2 = pv.vector(s2.left, s2.top), - p = p2.minus(p1), - v = p.perp().norm(), - w = v.times(s1.lineWidth / 2), - a = p1.plus(w), - b = p2.plus(w), - c = p2.minus(w), - d = p1.minus(w); - - /* - * Start join. P0 is the previous line segment's start point. We define the - * cutting plane as the average of the vector perpendicular to P0-P1, and - * the vector perpendicular to P1-P2. This insures that the cross-section of - * the line on the cutting plane is equal if the line-width is unchanged. - * Note that we don't implement miter limits, so these can get wild. - */ - if (i > 0) { - var s0 = scenes[i - 1]; - if (s0.visible) { - var v1 = p1.minus(s0.left, s0.top).perp().norm().plus(v); - d = intersect(p1, v1, d, p); - a = intersect(p1, v1, a, p); - } - } - - /* Similarly, for end join. */ - if (i < (n - 1)) { - var s3 = scenes[i + 2]; - if (s3.visible) { - var v2 = pv.vector(s3.left, s3.top).minus(p2).perp().norm().plus(v); - c = intersect(p2, v2, c, p); - b = intersect(p2, v2, b, p); - } - } - - /* points */ - var p = a.x + "," + a.y + " " - + b.x + "," + b.y + " " - + c.x + "," + c.y + " " - + d.x + "," + d.y; - - e = this.expect("polygon", e); - e.setAttribute("cursor", s1.cursor); - e.setAttribute("points", p); - e.setAttribute("fill", stroke.color); - e.setAttribute("fill-opacity", stroke.opacity); - e = this.append(e, scenes, i); - } - return e; -}; -var guid = 0; - -pv.SvgScene.panel = function(scenes) { - var g = scenes.$g, e = g && g.firstChild; - for (var i = 0; i < scenes.length; i++) { - var s = scenes[i]; - - /* visible */ - if (!s.visible) continue; - - /* svg */ - if (!scenes.parent) { - s.canvas.style.display = "inline-block"; - g = s.canvas.firstChild; - if (!g) { - g = s.canvas.appendChild(this.create("svg")); - g.onclick - = g.onmousedown - = g.onmouseup - = g.onmousemove - = g.onmouseout - = g.onmouseover - = pv.SvgScene.dispatch; - } - scenes.$g = g; - g.setAttribute("width", s.width + s.left + s.right); - g.setAttribute("height", s.height + s.top + s.bottom); - if (typeof e == "undefined") e = g.firstChild; - } - - /* clip (nest children) */ - if (s.overflow == "hidden") { - var c = this.expect("g", e), id = (guid++).toString(36); - c.setAttribute("clip-path", "url(#" + id + ")"); - if (!c.parentNode) g.appendChild(c); - scenes.$g = g = c; - e = c.firstChild; - - e = this.expect("clipPath", e); - e.setAttribute("id", id); - var r = e.firstChild || e.appendChild(this.create("rect")); - r.setAttribute("x", s.left); - r.setAttribute("y", s.top); - r.setAttribute("width", s.width); - r.setAttribute("height", s.height); - if (!e.parentNode) g.appendChild(e); - e = e.nextSibling; - } - - /* fill */ - e = this.fill(e, scenes, i); - - /* children */ - for (var j = 0; j < s.children.length; j++) { - s.children[j].$g = e = this.expect("g", e); - e.setAttribute("transform", "translate(" + s.left + "," + s.top + ")"); - this.updateAll(s.children[j]); - if (!e.parentNode) g.appendChild(e); - e = e.nextSibling; - } - - /* stroke */ - e = this.stroke(e, scenes, i); - - /* clip (restore group) */ - if (s.overflow == "hidden") { - scenes.$g = g = c.parentNode; - e = c.nextSibling; - } - } - return e; -}; - -pv.SvgScene.fill = function(e, scenes, i) { - var s = scenes[i], fill = pv.color(s.fillStyle); - if (fill.opacity) { - e = this.expect("rect", e); - e.setAttribute("x", s.left); - e.setAttribute("y", s.top); - e.setAttribute("width", s.width); - e.setAttribute("height", s.height); - e.setAttribute("cursor", s.cursor); - e.setAttribute("fill", fill.color); - e.setAttribute("fill-opacity", fill.opacity); - e = this.append(e, scenes, i); - } - return e; -}; - -pv.SvgScene.stroke = function(e, scenes, i) { - var s = scenes[i], stroke = pv.color(s.strokeStyle); - if (stroke.opacity) { - e = this.expect("rect", e); - e.setAttribute("x", s.left); - e.setAttribute("y", s.top); - e.setAttribute("width", Math.max(1E-10, s.width)); - e.setAttribute("height", Math.max(1E-10, s.height)); - e.setAttribute("cursor", s.cursor); - e.setAttribute("fill", "none"); - e.setAttribute("stroke", stroke.color); - e.setAttribute("stroke-opacity", stroke.opacity); - e.setAttribute("stroke-width", s.lineWidth); - e = this.append(e, scenes, i); - } - return e; -}; -pv.SvgScene.rule = function(scenes) { - var e = scenes.$g.firstChild; - for (var i = 0; i < scenes.length; i++) { - var s = scenes[i]; - - /* visible */ - if (!s.visible) continue; - var stroke = pv.color(s.strokeStyle); - if (!stroke.opacity) continue; - - e = this.expect("line", e); - e.setAttribute("cursor", s.cursor); - e.setAttribute("x1", s.left); - e.setAttribute("y1", s.top); - e.setAttribute("x2", s.left + s.width); - e.setAttribute("y2", s.top + s.height); - e.setAttribute("stroke", stroke.color); - e.setAttribute("stroke-opacity", stroke.opacity); - e.setAttribute("stroke-width", s.lineWidth); - e = this.append(e, scenes, i); - } - return e; -}; -pv.SvgScene.wedge = function(scenes) { - var e = scenes.$g.firstChild; - for (var i = 0; i < scenes.length; i++) { - var s = scenes[i]; - - /* visible */ - if (!s.visible) continue; - var fill = pv.color(s.fillStyle), stroke = pv.color(s.strokeStyle); - if (!fill.opacity && !stroke.opacity) continue; - - /* points */ - var r1 = s.innerRadius, r2 = s.outerRadius, a = Math.abs(s.angle), p; - if (a >= 2 * Math.PI) { - if (r1) { - p = "M0," + r2 - + "A" + r2 + "," + r2 + " 0 1,1 0," + (-r2) - + "A" + r2 + "," + r2 + " 0 1,1 0," + r2 - + "M0," + r1 - + "A" + r1 + "," + r1 + " 0 1,1 0," + (-r1) - + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 - + "Z"; - } else { - p = "M0," + r2 - + "A" + r2 + "," + r2 + " 0 1,1 0," + (-r2) - + "A" + r2 + "," + r2 + " 0 1,1 0," + r2 - + "Z"; - } - } else { - var sa = Math.min(s.startAngle, s.endAngle), - ea = Math.max(s.startAngle, s.endAngle), - c1 = Math.cos(sa), c2 = Math.cos(ea), - s1 = Math.sin(sa), s2 = Math.sin(ea); - if (r1) { - p = "M" + r2 * c1 + "," + r2 * s1 - + "A" + r2 + "," + r2 + " 0 " - + ((a < Math.PI) ? "0" : "1") + ",1 " - + r2 * c2 + "," + r2 * s2 - + "L" + r1 * c2 + "," + r1 * s2 - + "A" + r1 + "," + r1 + " 0 " - + ((a < Math.PI) ? "0" : "1") + ",0 " - + r1 * c1 + "," + r1 * s1 + "Z"; - } else { - p = "M" + r2 * c1 + "," + r2 * s1 - + "A" + r2 + "," + r2 + " 0 " - + ((a < Math.PI) ? "0" : "1") + ",1 " - + r2 * c2 + "," + r2 * s2 + "L0,0Z"; - } - } - - e = this.expect("path", e); - e.setAttribute("fill-rule", "evenodd"); - e.setAttribute("cursor", s.cursor); - e.setAttribute("transform", "translate(" + s.left + "," + s.top + ")"); - e.setAttribute("d", p); - e.setAttribute("fill", fill.color); - e.setAttribute("fill-opacity", fill.opacity); - e.setAttribute("stroke", stroke.color); - e.setAttribute("stroke-opacity", stroke.opacity); - e.setAttribute("stroke-width", s.lineWidth); - e = this.append(e, scenes, i); - } - return e; -}; -/** - * Constructs a new mark with default properties. Marks, with the exception of - * the root panel, are not typically constructed directly; instead, they are - * added to a panel or an existing mark via {@link pv.Mark#add}. - * - * @class Represents a data-driven graphical mark. The <tt>Mark</tt> class is - * the base class for all graphical marks in Protovis; it does not provide any - * specific rendering functionality, but together with {@link Panel} establishes - * the core framework. - * - * <p>Concrete mark types include familiar visual elements such as bars, lines - * and labels. Although a bar mark may be used to construct a bar chart, marks - * know nothing about charts; it is only through their specification and - * composition that charts are produced. These building blocks permit many - * combinatorial possibilities. - * - * <p>Marks are associated with <b>data</b>: a mark is generated once per - * associated datum, mapping the datum to visual <b>properties</b> such as - * position and color. Thus, a single mark specification represents a set of - * visual elements that share the same data and visual encoding. The type of - * mark defines the names of properties and their meaning. A property may be - * static, ignoring the associated datum and returning a constant; or, it may be - * dynamic, derived from the associated datum or index. Such dynamic encodings - * can be specified succinctly using anonymous functions. Special properties - * called event handlers can be registered to add interactivity. - * - * <p>Protovis uses <b>inheritance</b> to simplify the specification of related - * marks: a new mark can be derived from an existing mark, inheriting its - * properties. The new mark can then override properties to specify new - * behavior, potentially in terms of the old behavior. In this way, the old mark - * serves as the <b>prototype</b> for the new mark. Most mark types share the - * same basic properties for consistency and to facilitate inheritance. - * - * <p>The prioritization of redundant properties is as follows:<ol> - * - * <li>If the <tt>width</tt> property is not specified (i.e., null), its value - * is the width of the parent panel, minus this mark's left and right margins; - * the left and right margins are zero if not specified. - * - * <li>Otherwise, if the <tt>right</tt> margin is not specified, its value is - * the width of the parent panel, minus this mark's width and left margin; the - * left margin is zero if not specified. - * - * <li>Otherwise, if the <tt>left</tt> property is not specified, its value is - * the width of the parent panel, minus this mark's width and the right margin. - * - * </ol>This prioritization is then duplicated for the <tt>height</tt>, - * <tt>bottom</tt> and <tt>top</tt> properties, respectively. - * - * <p>While most properties are <i>variable</i>, some mark types, such as lines - * and areas, generate a single visual element rather than a distinct visual - * element per datum. With these marks, some properties may be <b>fixed</b>. - * Fixed properties can vary per mark, but not <i>per datum</i>! These - * properties are evaluated solely for the first (0-index) datum, and typically - * are specified as a constant. However, it is valid to use a function if the - * property varies between panels or is dynamically generated. - * - * <p>See also the <a href="../../api/">Protovis guide</a>. - */ -pv.Mark = function() { - /* - * TYPE 0 constant defs - * TYPE 1 function defs - * TYPE 2 constant properties - * TYPE 3 function properties - * in order of evaluation! - */ - this.$properties = []; -}; - -/** @private TOOD */ -pv.Mark.prototype.properties = {}; - -/** - * @private Defines and registers a property method for the property with the - * given name. This method should be called on a mark class prototype to define - * each exposed property. (Note this refers to the JavaScript - * <tt>prototype</tt>, not the Protovis mark prototype, which is the {@link - * #proto} field.) - * - * <p>The created property method supports several modes of invocation: <ol> - * - * <li>If invoked with a <tt>Function</tt> argument, this function is evaluated - * for each associated datum. The return value of the function is used as the - * computed property value. The context of the function (<tt>this</tt>) is this - * mark. The arguments to the function are the associated data of this mark and - * any enclosing panels. For example, a linear encoding of numerical data to - * height is specified as - * - * <pre>m.height(function(d) d * 100);</pre> - * - * The expression <tt>d * 100</tt> will be evaluated for the height property of - * each mark instance. The return value of the property method (e.g., - * <tt>m.height</tt>) is this mark (<tt>m</tt>)).<p> - * - * <li>If invoked with a non-function argument, the property is treated as a - * constant. The return value of the property method (e.g., <tt>m.height</tt>) - * is this mark.<p> - * - * <li>If invoked with no arguments, the computed property value for the current - * mark instance in the scene graph is returned. This facilitates <i>property - * chaining</i>, where one mark's properties are defined in terms of another's. - * For example, to offset a mark's location from its prototype, you might say - * - * <pre>m.top(function() this.proto.top() + 10);</pre> - * - * Note that the index of the mark being evaluated (in the above example, - * <tt>this.proto</tt>) is inherited from the <tt>Mark</tt> class and set by - * this mark. So, if the fifth element's top property is being evaluated, the - * fifth instance of <tt>this.proto</tt> will similarly be queried for the value - * of its top property. If the mark being evaluated has a different number of - * instances, or its data is unrelated, the behavior of this method is - * undefined. In these cases it may be better to index the <tt>scene</tt> - * explicitly to specify the exact instance. - * - * </ol><p>Property names should follow standard JavaScript method naming - * conventions, using lowerCamel-style capitalization. - * - * <p>In addition to creating the property method, every property is registered - * in the {@link #properties} map on the <tt>prototype</tt>. Although this is an - * instance field, it is considered immutable and shared by all instances of a - * given mark type. The <tt>properties</tt> map can be queried to see if a mark - * type defines a particular property, such as width or height. - * - * @param {string} name the property name. - */ -pv.Mark.prototype.property = function(name) { - if (!this.hasOwnProperty("properties")) { - this.properties = pv.extend(this.properties); - } - this.properties[name] = true; - - /* - * Define the setter-getter globally, since the default behavior should be the - * same for all properties, and since the Protovis inheritance chain is - * independent of the JavaScript inheritance chain. For example, anchors - * define a "name" property that is evaluated on derived marks, even though - * those marks don't normally have a name. - */ - pv.Mark.prototype[name] = function(v) { - if (arguments.length) { - this.$properties.push({ - name: name, - type: (typeof v == "function") ? 3 : 2, - value: v - }); - return this; - } - return this.scene[this.index][name]; - }; - - return this; -}; - -/* Define all global properties. */ -pv.Mark.prototype - .property("data") - .property("visible") - .property("left") - .property("right") - .property("top") - .property("bottom") - .property("cursor") - .property("title") - .property("reverse"); - -/** - * The mark type; a lower camelCase name. The type name controls rendering - * behavior, and unless the rendering engine is extended, must be one of the - * built-in concrete mark types: area, bar, dot, image, label, line, panel, - * rule, or wedge. - * - * @type string - * @name pv.Mark.prototype.type - */ - -/** - * The mark prototype, possibly undefined, from which to inherit property - * functions. The mark prototype is not necessarily of the same type as this - * mark. Any properties defined on this mark will override properties inherited - * either from the prototype or from the type-specific defaults. - * - * @type pv.Mark - * @name pv.Mark.prototype.proto - */ - -/** - * The enclosing parent panel. The parent panel is generally undefined only for - * the root panel; however, it is possible to create "offscreen" marks that are - * used only for inheritance purposes. - * - * @type pv.Panel - * @name pv.Mark.prototype.parent - */ - -/** - * The child index. -1 if the enclosing parent panel is null; otherwise, the - * zero-based index of this mark into the parent panel's <tt>children</tt> array. - * - * @type number - */ -pv.Mark.prototype.childIndex = -1; - -/** - * The mark index. The value of this field depends on which instance (i.e., - * which element of the data array) is currently being evaluated. During the - * build phase, the index is incremented over each datum; when handling events, - * the index is set to the instance that triggered the event. - * - * @type number - */ -pv.Mark.prototype.index = -1; - -/** - * The scene graph. The scene graph is an array of objects; each object (or - * "node") corresponds to an instance of this mark and an element in the data - * array. The scene graph can be traversed to lookup previously-evaluated - * properties. - * - * <p>For instance, consider a stacked area chart. The bottom property of the - * area can be defined using the <i>cousin</i> instance, which is the current - * area instance in the previous instantiation of the parent panel. In this - * sample code, - * - * <pre>new pv.Panel() - * .width(150).height(150) - * .add(pv.Panel) - * .data([[1, 1.2, 1.7, 1.5, 1.7], - * [.5, 1, .8, 1.1, 1.3], - * [.2, .5, .8, .9, 1]]) - * .add(pv.Area) - * .data(function(d) d) - * .bottom(function() { - * var c = this.cousin(); - * return c ? (c.bottom + c.height) : 0; - * }) - * .height(function(d) d * 40) - * .left(function() this.index * 35) - * .root.render();</pre> - * - * the bottom property is computed based on the upper edge of the corresponding - * datum in the previous series. The area's parent panel is instantiated once - * per series, so the cousin refers to the previous (below) area mark. (Note - * that the position of the upper edge is not the same as the top property, - * which refers to the top margin: the distance from the top edge of the panel - * to the top edge of the mark.) - * - * @see #first - * @see #last - * @see #sibling - * @see #cousin - * @name pv.Mark.prototype.scene - */ - -/** - * The root parent panel. This may be undefined for "offscreen" marks that are - * created for inheritance purposes only. - * - * @type pv.Panel - * @name pv.Mark.prototype.root - */ - -/** - * The data property; an array of objects. The size of the array determines the - * number of marks that will be instantiated; each element in the array will be - * passed to property functions to compute the property values. Typically, the - * data property is specified as a constant array, such as - * - * <pre>m.data([1, 2, 3, 4, 5]);</pre> - * - * However, it is perfectly acceptable to define the data property as a - * function. This function might compute the data dynamically, allowing - * different data to be used per enclosing panel. For instance, in the stacked - * area graph example (see {@link #scene}), the data function on the area mark - * dereferences each series. - * - * @type array - * @name pv.Mark.prototype.data - */ - -/** - * The visible property; a boolean determining whether or not the mark instance - * is visible. If a mark instance is not visible, its other properties will not - * be evaluated. Similarly, for panels no child marks will be rendered. - * - * @type boolean - * @name pv.Mark.prototype.visible - */ - -/** - * The left margin; the distance, in pixels, between the left edge of the - * enclosing panel and the left edge of this mark. Note that in some cases this - * property may be redundant with the right property, or with the conjunction of - * right and width. - * - * @type number - * @name pv.Mark.prototype.left - */ - -/** - * The right margin; the distance, in pixels, between the right edge of the - * enclosing panel and the right edge of this mark. Note that in some cases this - * property may be redundant with the left property, or with the conjunction of - * left and width. - * - * @type number - * @name pv.Mark.prototype.right - */ - -/** - * The top margin; the distance, in pixels, between the top edge of the - * enclosing panel and the top edge of this mark. Note that in some cases this - * property may be redundant with the bottom property, or with the conjunction - * of bottom and height. - * - * @type number - * @name pv.Mark.prototype.top - */ - -/** - * The bottom margin; the distance, in pixels, between the bottom edge of the - * enclosing panel and the bottom edge of this mark. Note that in some cases - * this property may be redundant with the top property, or with the conjunction - * of top and height. - * - * @type number - * @name pv.Mark.prototype.bottom - */ - -/** - * The cursor property; corresponds to the CSS cursor property. This is - * typically used in conjunction with event handlers to indicate interactivity. - * - * @type string - * @name pv.Mark.prototype.cursor - * @see <a href="http://www.w3.org/TR/CSS2/ui.html#propdef-cursor">CSS2 cursor</a> - */ - -/** - * The title property; corresponds to the HTML/SVG title property, allowing the - * general of simple plain text tooltips. - * - * @type string - * @name pv.Mark.prototype.title - */ - -/** - * The reverse property; a boolean determining whether marks are ordered from - * front-to-back or back-to-front. SVG does not support explicit z-ordering; - * shapes are rendered in the order they appear. Thus, by default, marks are - * rendered in data order. Setting the reverse property to false reverses the - * order in which they are rendered; however, the properties are still evaluated - * (i.e., built) in forward order. - * - * @type boolean - * @name pv.Mark.prototype.reverse - */ - -/** - * Default properties for all mark types. By default, the data array is the - * parent data as a single-element array; if the data property is not specified, - * this causes each mark to be instantiated as a singleton with the parents - * datum. The visible property is true by default, and the reverse property is - * false. - * - * @type pv.Mark - */ -pv.Mark.prototype.defaults = new pv.Mark() - .data(function(d) { return [d]; }) - .visible(true) - .reverse(false) - .cursor("") - .title(""); - -/* Private categorical colors for default fill & stroke styles. */ -var defaultFillStyle = pv.Colors.category20().by(pv.parent), - defaultStrokeStyle = pv.Colors.category10().by(pv.parent); - -/** - * Sets the prototype of this mark to the specified mark. Any properties not - * defined on this mark may be inherited from the specified prototype mark, or - * its prototype, and so on. The prototype mark need not be the same type of - * mark as this mark. (Note that for inheritance to be useful, properties with - * the same name on different mark types should have equivalent meaning.) - * - * @param {pv.Mark} proto the new prototype. - * @return {pv.Mark} this mark. - * @see #add - */ -pv.Mark.prototype.extend = function(proto) { - this.proto = proto; - return this; -}; - -/** - * Adds a new mark of the specified type to the enclosing parent panel, whilst - * simultaneously setting the prototype of the new mark to be this mark. - * - * @param {function} type the type of mark to add; a constructor, such as - * <tt>pv.Bar</tt>. - * @return {pv.Mark} the new mark. - * @see #extend - */ -pv.Mark.prototype.add = function(type) { - return this.parent.add(type).extend(this); -}; - -/** - * Defines a local variable on this mark. Local variables are initialized once - * per mark (i.e., per parent panel instance), and can be used to store local - * state for the mark. Here are a few reasons you might want to use - * <tt>def</tt>: - * - * <p>1. To store local state. For example, say you were visualizing employment - * statistics, and your root panel had an array of occupations. In a child - * panel, you might want to initialize a local scale, and reference it from a - * property function: - * - * <pre>.def("y", function(d) pv.Scale.linear(0, pv.max(d.values)).range(0, h)) - * .height(function(d) this.y()(d))</pre> - * - * In this example, <tt>this.y()</tt> returns the defined local scale. We then - * invoke the scale function, passing in the datum, to compute the height. Note - * that defs are similar to fixed properties: they are only evaluated once per - * parent panel, and <tt>this.y()</tt> returns a function, rather than - * automatically evaluating this function as a property. - * - * <p>2. To store temporary state for interaction. Say you have an array of - * bars, and you want to color the bar differently if the mouse is over it. Use - * <tt>def</tt> to define a local variable, and event handlers to override this - * variable interactively: - * - * <pre>.def("i", -1) - * .event("mouseover", function() this.i(this.index)) - * .event("mouseout", function() this.i(-1)) - * .fillStyle(function() this.i() == this.index ? "red" : "blue")</pre> - * - * Notice that <tt>this.i()</tt> can be used both to set the value of <i>i</i> - * (when an argument is specified), and to get the value of <i>i</i> (when no - * arguments are specified). In this way, it's like other property methods. - * - * <p>3. To specify fixed properties efficiently. Sometimes, the value of a - * property may be locally a constant, but dependent on parent panel data which - * is variable. In this scenario, you can use <tt>def</tt> to define a property; - * it will only get computed once per mark, rather than once per datum. - * - * @param {string} name the name of the local variable. - * @param {function} [value] an optional initializer; may be a constant or a - * function. - */ -pv.Mark.prototype.def = function(name, value) { - this.$properties.push({ - name: name, - type: (typeof value == "function") ? 1 : 0, - value: value - }); - return this; -}; - -/** - * Returns an anchor with the specified name. While anchor names are typically - * constants, the anchor name is a true property, which means you can specify a - * function to compute the anchor name dynamically. See the - * {@link pv.Anchor#name} property for details. - * - * @param {string} name the anchor name; either a string or a property function. - * @returns {pv.Anchor} the new anchor. - */ -pv.Mark.prototype.anchor = function(name) { - var anchor = new pv.Anchor().extend(this).name(name); - anchor.parent = this.parent; - return anchor; -}; - -/** - * Returns the anchor target of this mark, if it is derived from an anchor; - * otherwise returns null. For example, if a label is derived from a bar anchor, - * - * <pre>bar.anchor("top").add(pv.Label);</pre> - * - * then property functions on the label can refer to the bar via the - * <tt>anchorTarget</tt> method. This method is also useful for mark types - * defining properties on custom anchors. - * - * @returns {pv.Mark} the anchor target of this mark; possibly null. - */ -pv.Mark.prototype.anchorTarget = function() { - var target = this; - while (!(target instanceof pv.Anchor)) { - target = target.proto; - if (!target) return null; - } - return target.proto; -}; - -/** - * Returns the first instance of this mark in the scene graph. This method can - * only be called when the mark is bound to the scene graph (for example, from - * an event handler, or within a property function). - * - * @returns a node in the scene graph. - */ -pv.Mark.prototype.first = function() { - return this.scene[0]; -}; - -/** - * Returns the last instance of this mark in the scene graph. This method can - * only be called when the mark is bound to the scene graph (for example, from - * an event handler, or within a property function). In addition, note that mark - * instances are built sequentially, so the last instance of this mark may not - * yet be constructed. - * - * @returns a node in the scene graph. - */ -pv.Mark.prototype.last = function() { - return this.scene[this.scene.length - 1]; -}; - -/** - * Returns the previous instance of this mark in the scene graph, or null if - * this is the first instance. - * - * @returns a node in the scene graph, or null. - */ -pv.Mark.prototype.sibling = function() { - return (this.index == 0) ? null : this.scene[this.index - 1]; -}; - -/** - * Returns the current instance in the scene graph of this mark, in the previous - * instance of the enclosing parent panel. May return null if this instance - * could not be found. See the {@link pv.Layout.stack} function for an example - * property function using cousin. - * - * @see pv.Layout.stack - * @returns a node in the scene graph, or null. - */ -pv.Mark.prototype.cousin = function() { - var p = this.parent, s = p && p.sibling(); - return (s && s.children) ? s.children[this.childIndex][this.index] : null; -}; - -/** - * Renders this mark, including recursively rendering all child marks if this is - * a panel. - */ -pv.Mark.prototype.render = function() { - /* - * Rendering consists of three phases: bind, build and update. The update - * phase is decoupled to allow different rendering engines. - * - * In the bind phase, inherited property definitions are cached so they do not - * need to be queried during build. In the build phase, properties are - * evaluated, and the scene graph is generated. In the update phase, the scene - * is rendered by creating and updating elements and attributes in the SVG - * image. No properties are evaluated during the update phase; instead the - * values computed previously in the build phase are simply translated into - * SVG. - */ - this.bind(); - this.build(); - pv.Scene.updateAll(this.scene); -}; - -/** @private Computes the root data stack for the specified mark. */ -function argv(mark) { - var stack = []; - while (mark) { - stack.push(mark.scene[mark.index].data); - mark = mark.parent; - } - return stack; -} - -/** @private TODO */ -pv.Mark.prototype.bind = function() { - var seen = {}, types = [[], [], [], []], data, visible; - - /** TODO */ - function bind(mark) { - do { - var properties = mark.$properties; - for (var i = properties.length - 1; i >= 0 ; i--) { - var p = properties[i]; - if (!(p.name in seen)) { - seen[p.name] = 1; - switch (p.name) { - case "data": data = p; break; - case "visible": visible = p; break; - default: types[p.type].push(p); break; - } - } - } - } while (mark = mark.proto); - } - - /** TODO */ - function def(name) { - return function(v) { - var defs = this.scene.defs; - if (arguments.length) { - if (v == undefined) { - delete defs.locked[name]; - } else { - defs.locked[name] = true; - } - defs.values[name] = v; - return this; - } else { - return defs.values[name]; - } - }; - } - - /* Scan the proto chain for all defined properties. */ - bind(this); - bind(this.defaults); - types[1].reverse(); - types[3].reverse(); - - /* Any undefined properties are null. */ - var mark = this; - do for (var name in mark.properties) { - if (!(name in seen)) { - seen[name] = 1; - types[2].push({name: name, type: 2, value: null}); - } - } while (mark = mark.proto); - - /* Define setter-getter for inherited defs. */ - var defs = types[0].concat(types[1]); - for (var i = 0; i < defs.length; i++) { - var d = defs[i]; - this[d.name] = def(d.name); - } - - /* Setup binds to evaluate constants before functions. */ - this.binds = { - data: data, - visible: visible, - defs: defs, - properties: pv.blend(types) - }; -}; - -/** - * @private Evaluates properties and computes implied properties. Properties are - * stored in the {@link #scene} array for each instance of this mark. - * - * <p>As marks are built recursively, the {@link #index} property is updated to - * match the current index into the data array for each mark. Note that the - * index property is only set for the mark currently being built and its - * enclosing parent panels. The index property for other marks is unset, but is - * inherited from the global <tt>Mark</tt> class prototype. This allows mark - * properties to refer to properties on other marks <i>in the same panel</i> - * conveniently; however, in general it is better to reference mark instances - * specifically through the scene graph rather than depending on the magical - * behavior of {@link #index}. - * - * <p>The root scene array has a special property, <tt>data</tt>, which stores - * the current data stack. The first element in this stack is the current datum, - * followed by the datum of the enclosing parent panel, and so on. The data - * stack should not be accessed directly; instead, property functions are passed - * the current data stack as arguments. - * - * <p>The evaluation of the <tt>data</tt> and <tt>visible</tt> properties is - * special. The <tt>data</tt> property is evaluated first; unlike the other - * properties, the data stack is from the parent panel, rather than the current - * mark, since the data is not defined until the data property is evaluated. - * The <tt>visisble</tt> property is subsequently evaluated for each instance; - * only if true will the {@link #buildInstance} method be called, evaluating - * other properties and recursively building the scene graph. - * - * <p>If this mark is being re-built, any old instances of this mark that no - * longer exist (because the new data array contains fewer elements) will be - * cleared using {@link #clearInstance}. - * - * @param parent the instance of the parent panel from the scene graph. - */ -pv.Mark.prototype.build = function() { - var scene = this.scene; - if (!scene) { - scene = this.scene = []; - scene.mark = this; - scene.type = this.type; - scene.childIndex = this.childIndex; - if (this.parent) { - scene.parent = this.parent.scene; - scene.parentIndex = this.parent.index; - } - } - - /* Set the data stack. */ - var stack = this.root.scene.data; - if (!stack) this.root.scene.data = stack = argv(this.parent); - - /* Evaluate defs. */ - if (this.binds.defs.length) { - var defs = scene.defs; - if (!defs) scene.defs = defs = {values: {}, locked: {}}; - for (var i = 0; i < this.binds.defs.length; i++) { - var d = this.binds.defs[i]; - if (!(d.name in defs.locked)) { - var v = d.value; - if (d.type == 1) { - property = d.name; - v = v.apply(this, stack); - } - defs.values[d.name] = v; - } - } - } - - /* Evaluate special data property. */ - var data = this.binds.data; - switch (data.type) { - case 0: case 1: data = defs.values.data; break; - case 2: data = data.value; break; - case 3: { - property = "data"; - data = data.value.apply(this, stack); - break; - } - } - - /* Create, update and delete scene nodes. */ - stack.unshift(null); - scene.length = data.length; - for (var i = 0; i < data.length; i++) { - pv.Mark.prototype.index = this.index = i; - var s = scene[i]; - if (!s) scene[i] = s = {}; - s.data = stack[0] = data[i]; - - /* Evaluate special visible property. */ - var visible = this.binds.visible; - switch (visible.type) { - case 0: case 1: visible = defs.values.visible; break; - case 2: visible = visible.value; break; - case 3: { - property = "visible"; - visible = visible.value.apply(this, stack); - break; - } - } - - if (s.visible = visible) this.buildInstance(s); - } - stack.shift(); - delete this.index; - pv.Mark.prototype.index = -1; - if (!this.parent) scene.data = null; - - return this; -}; - -/** - * @private Evaluates the specified array of properties for the specified - * instance <tt>s</tt> in the scene graph. - * - * @param s a node in the scene graph; the instance of the mark to build. - * @param properties an array of properties. - */ -pv.Mark.prototype.buildProperties = function(s, properties) { - for (var i = 0, n = properties.length; i < n; i++) { - var p = properties[i], v = p.value; - switch (p.type) { - case 0: case 1: v = this.scene.defs.values[p.name]; break; - case 3: { - property = p.name; - v = v.apply(this, this.root.scene.data); - break; - } - } - s[p.name] = v; - } -}; - -/** - * @private Evaluates all of the properties for this mark for the specified - * instance <tt>s</tt> in the scene graph. The set of properties to evaluate is - * retrieved from the {@link #properties} array for this mark type (see {@link - * #type}). After these properties are evaluated, any <b>implied</b> properties - * may be computed by the mark and set on the scene graph; see - * {@link #buildImplied}. - * - * <p>For panels, this method recursively builds the scene graph for all child - * marks as well. In general, this method should not need to be overridden by - * concrete mark types. - * - * @param s a node in the scene graph; the instance of the mark to build. - */ -pv.Mark.prototype.buildInstance = function(s) { - this.buildProperties(s, this.binds.properties); - this.buildImplied(s); -}; - -/** - * @private Computes the implied properties for this mark for the specified - * instance <tt>s</tt> in the scene graph. Implied properties are those with - * dependencies on multiple other properties; for example, the width property - * may be implied if the left and right properties are set. This method can be - * overridden by concrete mark types to define new implied properties, if - * necessary. - * - * @param s a node in the scene graph; the instance of the mark to build. - */ -pv.Mark.prototype.buildImplied = function(s) { - var l = s.left; - var r = s.right; - var t = s.top; - var b = s.bottom; - - /* Assume width and height are zero if not supported by this mark type. */ - var p = this.properties; - var w = p.width ? s.width : 0; - var h = p.height ? s.height : 0; - - /* Compute implied width, right and left. */ - var width = this.parent ? this.parent.width() : (w + l + r); - if (w == null) { - w = width - (r = r || 0) - (l = l || 0); - } else if (r == null) { - r = width - w - (l = l || 0); - } else if (l == null) { - l = width - w - (r = r || 0); - } - - /* Compute implied height, bottom and top. */ - var height = this.parent ? this.parent.height() : (h + t + b); - if (h == null) { - h = height - (t = t || 0) - (b = b || 0); - } else if (b == null) { - b = height - h - (t = t || 0); - } else if (t == null) { - t = height - h - (b = b || 0); - } - - s.left = l; - s.right = r; - s.top = t; - s.bottom = b; - - /* Only set width and height if they are supported by this mark type. */ - if (p.width) s.width = w; - if (p.height) s.height = h; -}; - -/** - * @private The name of the property being evaluated, for so-called "smart" - * functions that change behavior depending on which property is being - * evaluated. This functionality is somewhat magical, so for now, this feature - * is not exposed outside the library. - * - * @type string - */ -var property; - -/** @private The current mouse location. */ -var pageX = 0, pageY = 0; -pv.listen(window, "mousemove", function(e) { pageX = e.pageX; pageY = e.pageY; }); - -/** - * Returns the current location of the mouse (cursor) relative to this mark's - * parent. The <i>x</i> coordinate corresponds to the left margin, while the - * <i>y</i> coordinate corresponds to the top margin. - * - * @returns {pv.Vector} the mouse location. - */ -pv.Mark.prototype.mouse = function() { - var x = 0, y = 0, mark = (this instanceof pv.Panel) ? this : this.parent; - do { - x += mark.left(); - y += mark.top(); - } while (mark = mark.parent); - var node = this.root.canvas(); - do { - x += node.offsetLeft; - y += node.offsetTop; - } while (node = node.offsetParent); - return pv.vector(pageX - x, pageY - y); -}; - -/** - * Registers an event handler for the specified event type with this mark. When - * an event of the specified type is triggered, the specified handler will be - * invoked. The handler is invoked in a similar method to property functions: - * the context is <tt>this</tt> mark instance, and the arguments are the full - * data stack. Event handlers can use property methods to manipulate the display - * properties of the mark: - * - * <pre>m.event("click", function() this.fillStyle("red"));</pre> - * - * Alternatively, the external data can be manipulated and the visualization - * redrawn: - * - * <pre>m.event("click", function(d) { - * data = all.filter(function(k) k.name == d); - * vis.render(); - * });</pre> - * - * The return value of the event handler determines which mark gets re-rendered. - * Use defs ({@link #def}) to set temporary state from event handlers. - * - * <p>The complete set of event types is defined by SVG; see the reference - * below. The set of supported event types is:<ul> - * - * <li>click - * <li>mousedown - * <li>mouseup - * <li>mouseover - * <li>mousemove - * <li>mouseout - * - * </ul>Since Protovis does not specify any concept of focus, it does not - * support key events; these should be handled outside the visualization using - * standard JavaScript. In the future, support for interaction may be extended - * to support additional event types, particularly those most relevant to - * interactive visualization, such as selection. - * - * <p>TODO In the current implementation, event handlers are not inherited from - * prototype marks. They must be defined explicitly on each interactive mark. In - * addition, only one event handler for a given event type can be defined; when - * specifying multiple event handlers for the same type, only the last one will - * be used. - * - * @see <a href="http://www.w3.org/TR/SVGTiny12/interact.html#SVGEvents">SVG events</a> - * @param {string} type the event type. - * @param {function} handler the event handler. - * @returns {pv.Mark} this. - */ -pv.Mark.prototype.event = function(type, handler) { - if (!this.$handlers) this.$handlers = {}; - this.$handlers[type] = handler; - return this; -}; - -/** @private TODO */ -pv.Mark.prototype.dispatch = function(type, scenes, index) { - var l = this.$handlers && this.$handlers[type]; - if (!l) { - if (this.parent) { - this.parent.dispatch(type, scenes.parent, scenes.parentIndex); - } - return; - } - try { - - /* Setup the scene stack. */ - var mark = this; - do { - mark.index = index; - mark.scene = scenes; - index = scenes.parentIndex; - scenes = scenes.parent; - } while (mark = mark.parent); - - /* Execute the event listener. */ - try { - mark = l.apply(this, this.root.scene.data = argv(this)); - } finally { - this.root.scene.data = null; - } - - /* Update the display. TODO dirtying. */ - if (mark instanceof pv.Mark) mark.render(); - - } finally { - - /* Restore the scene stack. */ - var mark = this; - do { - if (mark.parent) delete mark.scene; - delete mark.index; - } while (mark = mark.parent); - } -}; -/** - * Constructs a new mark anchor with default properties. - * - * @class Represents an anchor on a given mark. An anchor is itself a mark, but - * without a visual representation. It serves only to provide useful default - * properties that can be inherited by other marks. Each type of mark can define - * any number of named anchors for convenience. If the concrete mark type does - * not define an anchor implementation specifically, one will be inherited from - * the mark's parent class. - * - * <p>For example, the bar mark provides anchors for its four sides: left, - * right, top and bottom. Adding a label to the top anchor of a bar, - * - * <pre>bar.anchor("top").add(pv.Label);</pre> - * - * will render a text label on the top edge of the bar; the top anchor defines - * the appropriate position properties (top and left), as well as text-rendering - * properties for convenience (textAlign and textBaseline). - * - * @extends pv.Mark - */ -pv.Anchor = function() { - pv.Mark.call(this); -}; - -pv.Anchor.prototype = pv.extend(pv.Mark) - .property("name"); - -/** - * The anchor name. The set of supported anchor names is dependent on the - * concrete mark type; see the mark type for details. For example, bars support - * left, right, top and bottom anchors. - * - * <p>While anchor names are typically constants, the anchor name is a true - * property, which means you can specify a function to compute the anchor name - * dynamically. For instance, if you wanted to alternate top and bottom anchors, - * saying - * - * <pre>m.anchor(function() (this.index % 2) ? "top" : "bottom").add(pv.Dot);</pre> - * - * would have the desired effect. - * - * @type string - * @name pv.Anchor.prototype.name - */ -/** - * Constructs a new area mark with default properties. Areas are not typically - * constructed directly, but by adding to a panel or an existing mark via - * {@link pv.Mark#add}. - * - * @class Represents an area mark: the solid area between two series of - * connected line segments. Unsurprisingly, areas are used most frequently for - * area charts. - * - * <p>Just as a line represents a polyline, the <tt>Area</tt> mark type - * represents a <i>polygon</i>. However, an area is not an arbitrary polygon; - * vertices are paired either horizontally or vertically into parallel - * <i>spans</i>, and each span corresponds to an associated datum. Either the - * width or the height must be specified, but not both; this determines whether - * the area is horizontally-oriented or vertically-oriented. Like lines, areas - * can be stroked and filled with arbitrary colors. - * - * <p>See also the <a href="../../api/Area.html">Area guide</a>. - * - * @extends pv.Mark - */ -pv.Area = function() { - pv.Mark.call(this); -}; - -pv.Area.prototype = pv.extend(pv.Mark) - .property("width") - .property("height") - .property("lineWidth") - .property("strokeStyle") - .property("fillStyle") - .property("segmented") - .property("interpolate"); - -pv.Area.prototype.type = "area"; - -/** - * The width of a given span, in pixels; used for horizontal spans. If the width - * is specified, the height property should be 0 (the default). Either the top - * or bottom property should be used to space the spans vertically, typically as - * a multiple of the index. - * - * @type number - * @name pv.Area.prototype.width - */ - -/** - * The height of a given span, in pixels; used for vertical spans. If the height - * is specified, the width property should be 0 (the default). Either the left - * or right property should be used to space the spans horizontally, typically - * as a multiple of the index. - * - * @type number - * @name pv.Area.prototype.height - */ - -/** - * The width of stroked lines, in pixels; used in conjunction with - * <tt>strokeStyle</tt> to stroke the perimeter of the area. Unlike the - * {@link Line} mark type, the entire perimeter is stroked, rather than just one - * edge. The default value of this property is 1.5, but since the default stroke - * style is null, area marks are not stroked by default. - * - * <p>This property is <i>fixed</i> for non-segmented areas. See - * {@link pv.Mark}. - * - * @type number - * @name pv.Area.prototype.lineWidth - */ - -/** - * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to - * stroke the perimeter of the area. Unlike the {@link Line} mark type, the - * entire perimeter is stroked, rather than just one edge. The default value of - * this property is null, meaning areas are not stroked by default. - * - * <p>This property is <i>fixed</i> for non-segmented areas. See - * {@link pv.Mark}. - * - * @type string - * @name pv.Area.prototype.strokeStyle - * @see pv.color - */ - -/** - * The area fill style; if non-null, the interior of the polygon forming the - * area is filled with the specified color. The default value of this property - * is a categorical color. - * - * <p>This property is <i>fixed</i> for non-segmented areas. See - * {@link pv.Mark}. - * - * @type string - * @name pv.Area.prototype.fillStyle - * @see pv.color - */ - -/** - * Whether the area is segmented; whether variations in fill style, stroke - * style, and the other properties are treated as fixed. Rendering segmented - * areas is noticeably slower than non-segmented areas. - * - * <p>This property is <i>fixed</i>. See {@link pv.Mark}. - * - * @type boolean - * @name pv.Area.prototype.segmented - */ - -/** - * How to interpolate between values. Linear interpolation ("linear") is the - * default, producing a straight line between points. For piecewise constant - * functions (i.e., step functions), either "step-before" or "step-after" can be - * specified. - * - * <p>Note: this property is currently supported only on non-segmented areas. - * - * <p>This property is <i>fixed</i>. See {@link pv.Mark}. - * - * @type string - * @name pv.Area.prototype.interpolate - */ - -/** - * Default properties for areas. By default, there is no stroke and the fill - * style is a categorical color. - * - * @type pv.Area - */ -pv.Area.prototype.defaults = new pv.Area() - .extend(pv.Mark.prototype.defaults) - .lineWidth(1.5) - .fillStyle(defaultFillStyle) - .interpolate("linear"); - -/** - * Constructs a new area anchor with default properties. Areas support five - * different anchors:<ul> - * - * <li>top - * <li>left - * <li>center - * <li>bottom - * <li>right - * - * </ul>In addition to positioning properties (left, right, top bottom), the - * anchors support text rendering properties (text-align, text-baseline). Text is - * rendered to appear inside the area polygon. - * - * <p>To facilitate stacking of areas, the anchors are defined in terms of their - * opposite edge. For example, the top anchor defines the bottom property, such - * that the area grows upwards; the bottom anchor instead defines the top - * property, such that the area grows downwards. Of course, in general it is - * more robust to use panels and the cousin accessor to define stacked area - * marks; see {@link pv.Mark#scene} for an example. - * - * @param {string} name the anchor name; either a string or a property function. - * @returns {pv.Anchor} - */ -pv.Area.prototype.anchor = function(name) { - var area = this; - return pv.Mark.prototype.anchor.call(this, name) - .left(function() { - switch (this.name()) { - case "bottom": - case "top": - case "center": return area.left() + area.width() / 2; - case "right": return area.left() + area.width(); - } - return null; - }) - .right(function() { - switch (this.name()) { - case "bottom": - case "top": - case "center": return area.right() + area.width() / 2; - case "left": return area.right() + area.width(); - } - return null; - }) - .top(function() { - switch (this.name()) { - case "left": - case "right": - case "center": return area.top() + area.height() / 2; - case "bottom": return area.top() + area.height(); - } - return null; - }) - .bottom(function() { - switch (this.name()) { - case "left": - case "right": - case "center": return area.bottom() + area.height() / 2; - case "top": return area.bottom() + area.height(); - } - return null; - }) - .textAlign(function() { - switch (this.name()) { - case "bottom": - case "top": - case "center": return "center"; - case "right": return "right"; - } - return "left"; - }) - .textBaseline(function() { - switch (this.name()) { - case "right": - case "left": - case "center": return "middle"; - case "top": return "top"; - } - return "bottom"; - }); -}; - -/** - * @private Overrides the default behavior of {@link pv.Mark.buildImplied} such - * that the width and height are set to zero if null. - * - * @param s a node in the scene graph; the instance of the mark to build. - */ -pv.Area.prototype.buildImplied = function(s) { - if (s.height == null) s.height = 0; - if (s.width == null) s.width = 0; - pv.Mark.prototype.buildImplied.call(this, s); -}; - -/** @private */ -var pv_Area_specials = {left:1, top:1, right:1, bottom:1, width:1, height:1, name:1}; - -/** @private */ -pv.Area.prototype.bind = function() { - pv.Mark.prototype.bind.call(this); - var binds = this.binds, - properties = binds.properties, - specials = binds.specials = []; - for (var i = 0, n = properties.length; i < n; i++) { - var p = properties[i]; - if (p.name in pv_Area_specials) specials.push(p); - } -}; - -/** @private */ -pv.Area.prototype.buildInstance = function(s) { - if (this.index && !this.scene[0].segmented) { - this.buildProperties(s, this.binds.specials); - this.buildImplied(s); - } else { - pv.Mark.prototype.buildInstance.call(this, s); - } -}; -/** - * Constructs a new bar mark with default properties. Bars are not typically - * constructed directly, but by adding to a panel or an existing mark via - * {@link pv.Mark#add}. - * - * @class Represents a bar: an axis-aligned rectangle that can be stroked and - * filled. Bars are used for many chart types, including bar charts, histograms - * and Gantt charts. Bars can also be used as decorations, for example to draw a - * frame border around a panel; in fact, a panel is a special type (a subclass) - * of bar. - * - * <p>Bars can be positioned in several ways. Most commonly, one of the four - * corners is fixed using two margins, and then the width and height properties - * determine the extent of the bar relative to this fixed location. For example, - * using the bottom and left properties fixes the bottom-left corner; the width - * then extends to the right, while the height extends to the top. As an - * alternative to the four corners, a bar can be positioned exclusively using - * margins; this is convenient as an inset from the containing panel, for - * example. See {@link pv.Mark} for details on the prioritization of redundant - * positioning properties. - * - * <p>See also the <a href="../../api/Bar.html">Bar guide</a>. - * - * @extends pv.Mark - */ -pv.Bar = function() { - pv.Mark.call(this); -}; - -pv.Bar.prototype = pv.extend(pv.Mark) - .property("width") - .property("height") - .property("lineWidth") - .property("strokeStyle") - .property("fillStyle"); - -pv.Bar.prototype.type = "bar"; - -/** - * The width of the bar, in pixels. If the left position is specified, the bar - * extends rightward from the left edge; if the right position is specified, the - * bar extends leftward from the right edge. - * - * @type number - * @name pv.Bar.prototype.width - */ - -/** - * The height of the bar, in pixels. If the bottom position is specified, the - * bar extends upward from the bottom edge; if the top position is specified, - * the bar extends downward from the top edge. - * - * @type number - * @name pv.Bar.prototype.height - */ - -/** - * The width of stroked lines, in pixels; used in conjunction with - * <tt>strokeStyle</tt> to stroke the bar's border. - * - * @type number - * @name pv.Bar.prototype.lineWidth - */ - -/** - * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to - * stroke the bar's border. The default value of this property is null, meaning - * bars are not stroked by default. - * - * @type string - * @name pv.Bar.prototype.strokeStyle - * @see pv.color - */ - -/** - * The bar fill style; if non-null, the interior of the bar is filled with the - * specified color. The default value of this property is a categorical color. - * - * @type string - * @name pv.Bar.prototype.fillStyle - * @see pv.color - */ - -/** - * Default properties for bars. By default, there is no stroke and the fill - * style is a categorical color. - * - * @type pv.Bar - */ -pv.Bar.prototype.defaults = new pv.Bar() - .extend(pv.Mark.prototype.defaults) - .lineWidth(1.5) - .fillStyle(defaultFillStyle); - -/** - * Constructs a new bar anchor with default properties. Bars support five - * different anchors:<ul> - * - * <li>top - * <li>left - * <li>center - * <li>bottom - * <li>right - * - * </ul>In addition to positioning properties (left, right, top bottom), the - * anchors support text rendering properties (text-align, text-baseline). Text - * is rendered to appear inside the bar. - * - * <p>To facilitate stacking of bars, the anchors are defined in terms of their - * opposite edge. For example, the top anchor defines the bottom property, such - * that the bar grows upwards; the bottom anchor instead defines the top - * property, such that the bar grows downwards. Of course, in general it is more - * robust to use panels and the cousin accessor to define stacked bars; see - * {@link pv.Mark#scene} for an example. - * - * <p>Bar anchors also "smartly" specify position properties based on whether - * the derived mark type supports the width and height properties. If the - * derived mark type does not support these properties (e.g., dots), the - * position will be centered on the corresponding edge. Otherwise (e.g., bars), - * the position will be in the opposite side. - * - * @param {string} name the anchor name; either a string or a property function. - * @returns {pv.Anchor} - */ -pv.Bar.prototype.anchor = function(name) { - var bar = this; - return pv.Mark.prototype.anchor.call(this, name) - .left(function() { - switch (this.name()) { - case "bottom": - case "top": - case "center": return bar.left() + (this.properties.width ? 0 : (bar.width() / 2)); - case "right": return bar.left() + bar.width(); - } - return null; - }) - .right(function() { - switch (this.name()) { - case "bottom": - case "top": - case "center": return bar.right() + (this.properties.width ? 0 : (bar.width() / 2)); - case "left": return bar.right() + bar.width(); - } - return null; - }) - .top(function() { - switch (this.name()) { - case "left": - case "right": - case "center": return bar.top() + (this.properties.height ? 0 : (bar.height() / 2)); - case "bottom": return bar.top() + bar.height(); - } - return null; - }) - .bottom(function() { - switch (this.name()) { - case "left": - case "right": - case "center": return bar.bottom() + (this.properties.height ? 0 : (bar.height() / 2)); - case "top": return bar.bottom() + bar.height(); - } - return null; - }) - .textAlign(function() { - switch (this.name()) { - case "bottom": - case "top": - case "center": return "center"; - case "right": return "right"; - } - return "left"; - }) - .textBaseline(function() { - switch (this.name()) { - case "right": - case "left": - case "center": return "middle"; - case "top": return "top"; - } - return "bottom"; - }); -}; -/** - * Constructs a new dot mark with default properties. Dots are not typically - * constructed directly, but by adding to a panel or an existing mark via - * {@link pv.Mark#add}. - * - * @class Represents a dot; a dot is simply a sized glyph centered at a given - * point that can also be stroked and filled. The <tt>size</tt> property is - * proportional to the area of the rendered glyph to encourage meaningful visual - * encodings. Dots can visually encode up to eight dimensions of data, though - * this may be unwise due to integrality. See {@link pv.Mark} for details on the - * prioritization of redundant positioning properties. - * - * <p>See also the <a href="../../api/Dot.html">Dot guide</a>. - * - * @extends pv.Mark - */ -pv.Dot = function() { - pv.Mark.call(this); -}; - -pv.Dot.prototype = pv.extend(pv.Mark) - .property("size") - .property("shape") - .property("angle") - .property("lineWidth") - .property("strokeStyle") - .property("fillStyle"); - -pv.Dot.prototype.type = "dot"; - -/** - * The size of the dot, in square pixels. Square pixels are used such that the - * area of the dot is linearly proportional to the value of the size property, - * facilitating representative encodings. - * - * @see #radius - * @type number - * @name pv.Dot.prototype.size - */ - -/** - * The shape name. Several shapes are supported:<ul> - * - * <li>cross - * <li>triangle - * <li>diamond - * <li>square - * <li>tick - * <li>circle - * - * </ul>These shapes can be further changed using the {@link #angle} property; - * for instance, a cross can be turned into a plus by rotating. Similarly, the - * tick, which is vertical by default, can be rotated horizontally. Note that - * some shapes (cross and tick) do not have interior areas, and thus do not - * support fill style meaningfully. - * - * <p>Note: it may be more natural to use the {@link pv.Rule} mark for - * horizontal and vertical ticks. The tick shape is only necessary if angled - * ticks are needed. - * - * @type string - * @name pv.Dot.prototype.shape - */ - -/** - * The rotation angle, in radians. Used to rotate shapes, such as to turn a - * cross into a plus. - * - * @type number - * @name pv.Dot.prototype.angle - */ - -/** - * The width of stroked lines, in pixels; used in conjunction with - * <tt>strokeStyle</tt> to stroke the dot's shape. - * - * @type number - * @name pv.Dot.prototype.lineWidth - */ - -/** - * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to - * stroke the dot's shape. The default value of this property is a categorical - * color. - * - * @type string - * @name pv.Dot.prototype.strokeStyle - * @see pv.color - */ - -/** - * The fill style; if non-null, the interior of the dot is filled with the - * specified color. The default value of this property is null, meaning dots are - * not filled by default. - * - * @type string - * @name pv.Dot.prototype.fillStyle - * @see pv.color - */ - -/** - * Default properties for dots. By default, there is no fill and the stroke - * style is a categorical color. The default shape is "circle" with size 20. - * - * @type pv.Dot - */ -pv.Dot.prototype.defaults = new pv.Dot() - .extend(pv.Mark.prototype.defaults) - .size(20) - .shape("circle") - .lineWidth(1.5) - .strokeStyle(defaultStrokeStyle); - -/** - * Constructs a new dot anchor with default properties. Dots support five - * different anchors:<ul> - * - * <li>top - * <li>left - * <li>center - * <li>bottom - * <li>right - * - * </ul>In addition to positioning properties (left, right, top bottom), the - * anchors support text rendering properties (text-align, text-baseline). Text is - * rendered to appear outside the dot. Note that this behavior is different from - * other mark anchors, which default to rendering text <i>inside</i> the mark. - * - * <p>For consistency with the other mark types, the anchor positions are - * defined in terms of their opposite edge. For example, the top anchor defines - * the bottom property, such that a bar added to the top anchor grows upward. - * - * @param {string} name the anchor name; either a string or a property function. - * @returns {pv.Anchor} - */ -pv.Dot.prototype.anchor = function(name) { - var dot = this; - return pv.Mark.prototype.anchor.call(this, name) - .left(function(d) { - switch (this.name()) { - case "bottom": - case "top": - case "center": return dot.left(); - case "right": return dot.left() + dot.radius(); - } - return null; - }) - .right(function(d) { - switch (this.name()) { - case "bottom": - case "top": - case "center": return dot.right(); - case "left": return dot.right() + dot.radius(); - } - return null; - }) - .top(function(d) { - switch (this.name()) { - case "left": - case "right": - case "center": return dot.top(); - case "bottom": return dot.top() + dot.radius(); - } - return null; - }) - .bottom(function(d) { - switch (this.name()) { - case "left": - case "right": - case "center": return dot.bottom(); - case "top": return dot.bottom() + dot.radius(); - } - return null; - }) - .textAlign(function(d) { - switch (this.name()) { - case "left": return "right"; - case "bottom": - case "top": - case "center": return "center"; - } - return "left"; - }) - .textBaseline(function(d) { - switch (this.name()) { - case "right": - case "left": - case "center": return "middle"; - case "bottom": return "top"; - } - return "bottom"; - }); -}; - -/** - * Returns the radius of the dot, which is defined to be the square root of the - * {@link #size} property. - * - * @returns {number} the radius. - */ -pv.Dot.prototype.radius = function() { - return Math.sqrt(this.size()); -}; -/** - * Constructs a new label mark with default properties. Labels are not typically - * constructed directly, but by adding to a panel or an existing mark via - * {@link pv.Mark#add}. - * - * @class Represents a text label, allowing textual annotation of other marks or - * arbitrary text within the visualization. The character data must be plain - * text (unicode), though the text can be styled using the {@link #font} - * property. If rich text is needed, external HTML elements can be overlaid on - * the canvas by hand. - * - * <p>Labels are positioned using the box model, similarly to {@link Dot}. Thus, - * a label has no width or height, but merely a text anchor location. The text - * is positioned relative to this anchor location based on the - * {@link #textAlign}, {@link #textBaseline} and {@link #textMargin} properties. - * Furthermore, the text may be rotated using {@link #textAngle}. - * - * <p>Labels ignore events, so as to not interfere with event handlers on - * underlying marks, such as bars. In the future, we may support event handlers - * on labels. - * - * <p>See also the <a href="../../api/Label.html">Label guide</a>. - * - * @extends pv.Mark - */ -pv.Label = function() { - pv.Mark.call(this); -}; - -pv.Label.prototype = pv.extend(pv.Mark) - .property("text") - .property("font") - .property("textAngle") - .property("textStyle") - .property("textAlign") - .property("textBaseline") - .property("textMargin") - .property("textShadow"); - -pv.Label.prototype.type = "label"; - -/** - * The character data to render; a string. The default value of the text - * property is the identity function, meaning the label's associated datum will - * be rendered using its <tt>toString</tt>. - * - * @type string - * @name pv.Label.prototype.text - */ - -/** - * The font format, per the CSS Level 2 specification. The default font is "10px - * sans-serif", for consistency with the HTML 5 canvas element specification. - * Note that since text is not wrapped, any line-height property will be - * ignored. The other font-style, font-variant, font-weight, font-size and - * font-family properties are supported. - * - * @see <a href="http://www.w3.org/TR/CSS2/fonts.html#font-shorthand">CSS2 fonts</a> - * @type string - * @name pv.Label.prototype.font - */ - -/** - * The rotation angle, in radians. Text is rotated clockwise relative to the - * anchor location. For example, with the default left alignment, an angle of - * Math.PI / 2 causes text to proceed downwards. The default angle is zero. - * - * @type number - * @name pv.Label.prototype.textAngle - */ - -/** - * The text color. The name "textStyle" is used for consistency with "fillStyle" - * and "strokeStyle", although it might be better to rename this property (and - * perhaps use the same name as "strokeStyle"). The default color is black. - * - * @type string - * @name pv.Label.prototype.textStyle - * @see pv.color - */ - -/** - * The horizontal text alignment. One of:<ul> - * - * <li>left - * <li>center - * <li>right - * - * </ul>The default horizontal alignment is left. - * - * @type string - * @name pv.Label.prototype.textAlign - */ - -/** - * The vertical text alignment. One of:<ul> - * - * <li>top - * <li>middle - * <li>bottom - * - * </ul>The default vertical alignment is bottom. - * - * @type string - * @name pv.Label.prototype.textBaseline - */ - -/** - * The text margin; may be specified in pixels, or in font-dependent units (such - * as ".1ex"). The margin can be used to pad text away from its anchor location, - * in a direction dependent on the horizontal and vertical alignment - * properties. For example, if the text is left- and middle-aligned, the margin - * shifts the text to the right. The default margin is 3 pixels. - * - * @type number - * @name pv.Label.prototype.textMargin - */ - -/** - * A list of shadow effects to be applied to text, per the CSS Text Level 3 - * text-shadow property. An example specification is "0.1em 0.1em 0.1em - * rgba(0,0,0,.5)"; the first length is the horizontal offset, the second the - * vertical offset, and the third the blur radius. - * - * @see <a href="http://www.w3.org/TR/css3-text/#text-shadow">CSS3 text</a> - * @type string - * @name pv.Label.prototype.textShadow - */ - -/** - * Default properties for labels. See the individual properties for the default - * values. - * - * @type pv.Label - */ -pv.Label.prototype.defaults = new pv.Label() - .extend(pv.Mark.prototype.defaults) - .text(pv.identity) - .font("10px sans-serif") - .textAngle(0) - .textStyle("black") - .textAlign("left") - .textBaseline("bottom") - .textMargin(3); -/** - * Constructs a new line mark with default properties. Lines are not typically - * constructed directly, but by adding to a panel or an existing mark via - * {@link pv.Mark#add}. - * - * @class Represents a series of connected line segments, or <i>polyline</i>, - * that can be stroked with a configurable color and thickness. Each - * articulation point in the line corresponds to a datum; for <i>n</i> points, - * <i>n</i>-1 connected line segments are drawn. The point is positioned using - * the box model. Arbitrary paths are also possible, allowing radar plots and - * other custom visualizations. - * - * <p>Like areas, lines can be stroked and filled with arbitrary colors. In most - * cases, lines are only stroked, but the fill style can be used to construct - * arbitrary polygons. - * - * <p>See also the <a href="../../api/Line.html">Line guide</a>. - * - * @extends pv.Mark - */ -pv.Line = function() { - pv.Mark.call(this); -}; - -pv.Line.prototype = pv.extend(pv.Mark) - .property("lineWidth") - .property("strokeStyle") - .property("fillStyle") - .property("segmented") - .property("interpolate"); - -pv.Line.prototype.type = "line"; - -/** - * The width of stroked lines, in pixels; used in conjunction with - * <tt>strokeStyle</tt> to stroke the line. - * - * @type number - * @name pv.Line.prototype.lineWidth - */ - -/** - * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to - * stroke the line. The default value of this property is a categorical color. - * - * @type string - * @name pv.Line.prototype.strokeStyle - * @see pv.color - */ - -/** - * The line fill style; if non-null, the interior of the line is closed and - * filled with the specified color. The default value of this property is a - * null, meaning that lines are not filled by default. - * - * @type string - * @name pv.Line.prototype.fillStyle - * @see pv.color - */ - -/** - * Whether the line is segmented; whether variations in stroke style, line width - * and the other properties are treated as fixed. Rendering segmented lines is - * noticeably slower than non-segmented lines. - * - * <p>This property is <i>fixed</i>. See {@link pv.Mark}. - * - * @type boolean - * @name pv.Line.prototype.segmented - */ - -/** - * How to interpolate between values. Linear interpolation ("linear") is the - * default, producing a straight line between points. For piecewise constant - * functions (i.e., step functions), either "step-before" or "step-after" can be - * specified. - * - * <p>Note: this property is currently supported only on non-segmented lines. - * - * <p>This property is <i>fixed</i>. See {@link pv.Mark}. - * - * @type string - * @name pv.Line.prototype.interpolate - */ - -/** - * Default properties for lines. By default, there is no fill and the stroke - * style is a categorical color. The default interpolation is linear. - * - * @type pv.Line - */ -pv.Line.prototype.defaults = new pv.Line() - .extend(pv.Mark.prototype.defaults) - .lineWidth(1.5) - .strokeStyle(defaultStrokeStyle) - .interpolate("linear"); - -/** @private */ -var pv_Line_specials = {left:1, top:1, right:1, bottom:1, name:1}; - -/** @private */ -pv.Line.prototype.bind = function() { - pv.Mark.prototype.bind.call(this); - var binds = this.binds, - properties = binds.properties, - specials = binds.specials = []; - for (var i = 0, n = properties.length; i < n; i++) { - var p = properties[i]; - if (p.name in pv_Line_specials) specials.push(p); - } -}; - -/** @private */ -pv.Line.prototype.buildInstance = function(s) { - if (this.index && !this.scene[0].segmented) { - this.buildProperties(s, this.binds.specials); - this.buildImplied(s); - } else { - pv.Mark.prototype.buildInstance.call(this, s); - } -}; -/** - * Constructs a new rule with default properties. Rules are not typically - * constructed directly, but by adding to a panel or an existing mark via - * {@link pv.Mark#add}. - * - * @class Represents a horizontal or vertical rule. Rules are frequently used - * for axes and grid lines. For example, specifying only the bottom property - * draws horizontal rules, while specifying only the left draws vertical - * rules. Rules can also be used as thin bars. The visual style is controlled in - * the same manner as lines. - * - * <p>Rules are positioned exclusively the standard box model properties. The - * following combinations of properties are supported: - * - * <table> - * <thead><th style="width:12em;">Properties</th><th>Orientation</th></thead> - * <tbody> - * <tr><td>left</td><td>vertical</td></tr> - * <tr><td>right</td><td>vertical</td></tr> - * <tr><td>left, bottom, top</td><td>vertical</td></tr> - * <tr><td>right, bottom, top</td><td>vertical</td></tr> - * <tr><td>top</td><td>horizontal</td></tr> - * <tr><td>bottom</td><td>horizontal</td></tr> - * <tr><td>top, left, right</td><td>horizontal</td></tr> - * <tr><td>bottom, left, right</td><td>horizontal</td></tr> - * <tr><td>left, top, height</td><td>vertical</td></tr> - * <tr><td>left, bottom, height</td><td>vertical</td></tr> - * <tr><td>right, top, height</td><td>vertical</td></tr> - * <tr><td>right, bottom, height</td><td>vertical</td></tr> - * <tr><td>left, top, width</td><td>horizontal</td></tr> - * <tr><td>left, bottom, width</td><td>horizontal</td></tr> - * <tr><td>right, top, width</td><td>horizontal</td></tr> - * <tr><td>right, bottom, width</td><td>horizontal</td></tr> - * </tbody> - * </table> - * - * <p>Small rules can be used as tick marks; alternatively, a {@link Dot} with - * the "tick" shape can be used. - * - * <p>See also the <a href="../../api/Rule.html">Rule guide</a>. - * - * @see pv.Line - * @extends pv.Mark - */ -pv.Rule = function() { - pv.Mark.call(this); -}; - -pv.Rule.prototype = pv.extend(pv.Mark) - .property("width") - .property("height") - .property("lineWidth") - .property("strokeStyle"); - -pv.Rule.prototype.type = "rule"; - -/** - * The width of the rule, in pixels. If the left position is specified, the rule - * extends rightward from the left edge; if the right position is specified, the - * rule extends leftward from the right edge. - * - * @type number - * @name pv.Rule.prototype.width - */ - -/** - * The height of the rule, in pixels. If the bottom position is specified, the - * rule extends upward from the bottom edge; if the top position is specified, - * the rule extends downward from the top edge. - * - * @type number - * @name pv.Rule.prototype.height - */ - -/** - * The width of stroked lines, in pixels; used in conjunction with - * <tt>strokeStyle</tt> to stroke the rule. The default value is 1 pixel. - * - * @type number - * @name pv.Rule.prototype.lineWidth - */ - -/** - * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to - * stroke the rule. The default value of this property is black. - * - * @type string - * @name pv.Rule.prototype.strokeStyle - * @see pv.color - */ - -/** - * Default properties for rules. By default, a single-pixel black line is - * stroked. - * - * @type pv.Rule - */ -pv.Rule.prototype.defaults = new pv.Rule() - .extend(pv.Mark.prototype.defaults) - .lineWidth(1) - .strokeStyle("black"); - -/** - * Constructs a new rule anchor with default properties. Rules support five - * different anchors:<ul> - * - * <li>top - * <li>left - * <li>center - * <li>bottom - * <li>right - * - * </ul>In addition to positioning properties (left, right, top bottom), the - * anchors support text rendering properties (text-align, text-baseline). Text is - * rendered to appear outside the rule. Note that this behavior is different - * from other mark anchors, which default to rendering text <i>inside</i> the - * mark. - * - * <p>For consistency with the other mark types, the anchor positions are - * defined in terms of their opposite edge. For example, the top anchor defines - * the bottom property, such that a bar added to the top anchor grows upward. - * - * @param {string} name the anchor name; either a string or a property function. - * @returns {pv.Anchor} - */ -pv.Rule.prototype.anchor = function(name) { - return pv.Bar.prototype.anchor.call(this, name) - .textAlign(function(d) { - switch (this.name()) { - case "left": return "right"; - case "bottom": - case "top": - case "center": return "center"; - case "right": return "left"; - } - }) - .textBaseline(function(d) { - switch (this.name()) { - case "right": - case "left": - case "center": return "middle"; - case "top": return "bottom"; - case "bottom": return "top"; - } - }); -}; - -/** - * @private Overrides the default behavior of {@link pv.Mark.buildImplied} to - * determine the orientation (vertical or horizontal) of the rule. - * - * @param s a node in the scene graph; the instance of the rule to build. - */ -pv.Rule.prototype.buildImplied = function(s) { - var l = s.left, r = s.right, t = s.top, b = s.bottom; - - /* Determine horizontal or vertical orientation. */ - if ((s.width != null) - || ((l == null) && (r == null)) - || ((r != null) && (l != null))) { - s.height = 0; - } else { - s.width = 0; - } - - pv.Mark.prototype.buildImplied.call(this, s); -}; -/** - * Constructs a new, empty panel with default properties. Panels, with the - * exception of the root panel, are not typically constructed directly; instead, - * they are added to an existing panel or mark via {@link pv.Mark#add}. - * - * @class Represents a container mark. Panels allow repeated or nested - * structures, commonly used in small multiple displays where a small - * visualization is tiled to facilitate comparison across one or more - * dimensions. Other types of visualizations may benefit from repeated and - * possibly overlapping structure as well, such as stacked area charts. Panels - * can also offset the position of marks to provide padding from surrounding - * content. - * - * <p>All Protovis displays have at least one panel; this is the root panel to - * which marks are rendered. The box model properties (four margins, width and - * height) are used to offset the positions of contained marks. The data - * property determines the panel count: a panel is generated once per associated - * datum. When nested panels are used, property functions can declare additional - * arguments to access the data associated with enclosing panels. - * - * <p>Panels can be rendered inline, facilitating the creation of sparklines. - * This allows designers to reuse browser layout features, such as text flow and - * tables; designers can also overlay HTML elements such as rich text and - * images. - * - * <p>All panels have a <tt>children</tt> array (possibly empty) containing the - * child marks in the order they were added. Panels also have a <tt>root</tt> - * field which points to the root (outermost) panel; the root panel's root field - * points to itself. - * - * <p>See also the <a href="../../api/">Protovis guide</a>. - * - * @extends pv.Bar - */ -pv.Panel = function() { - pv.Bar.call(this); - - /** - * The child marks; zero or more {@link pv.Mark}s in the order they were - * added. - * - * @see #add - * @type pv.Mark[] - */ - this.children = []; - this.root = this; - - /** - * The internal $dom field is set by the Protovis loader; see lang/init.js. It - * refers to the script element that contains the Protovis specification, so - * that the panel knows where in the DOM to insert the generated SVG element. - * - * @private - */ - this.$dom = pv.Panel.$dom; -}; - -pv.Panel.prototype = pv.extend(pv.Bar) - .property("canvas") - .property("overflow"); - -pv.Panel.prototype.type = "panel"; - -/** - * The canvas element; either the string ID of the canvas element in the current - * document, or a reference to the canvas element itself. If null, a canvas - * element will be created and inserted into the document at the location of the - * script element containing the current Protovis specification. This property - * only applies to root panels and is ignored on nested panels. - * - * <p>Note: the "canvas" element here refers to a <tt>div</tt> (or other suitable - * HTML container element), <i>not</i> a <tt>canvas</tt> element. The name of - * this property is a historical anachronism from the first implementation that - * used HTML 5 canvas, rather than SVG. - * - * @type string - * @name pv.Panel.prototype.canvas - */ - -/** - * Default properties for panels. By default, the margins are zero, the fill - * style is transparent. - * - * @type pv.Panel - */ -pv.Panel.prototype.defaults = new pv.Panel() - .extend(pv.Bar.prototype.defaults) - .fillStyle(null) - .overflow("visible"); - -/** - * Returns an anchor with the specified name. This method is overridden since - * the behavior of Panel anchors is slightly different from normal anchors: - * adding to an anchor adds to the anchor target's, rather than the anchor - * target's parent. To avoid double margins, we override the anchor's proto so - * that the margins are zero. - * - * @param {string} name the anchor name; either a string or a property function. - * @returns {pv.Anchor} the new anchor. - */ -pv.Panel.prototype.anchor = function(name) { - - /* A "view" of this panel whose margins appear to be zero. */ - function z() { return 0; } - z.prototype = this; - z.prototype.left = z.prototype.right = z.prototype.top = z.prototype.bottom = z; - - var anchor = pv.Bar.prototype.anchor.call(new z(), name) - .data(function(d) { return [d]; }); - anchor.parent = this; - return anchor; -}; - -/** - * Adds a new mark of the specified type to this panel. Unlike the normal - * {@link Mark#add} behavior, adding a mark to a panel does not cause the mark - * to inherit from the panel. Since the contained marks are offset by the panel - * margins already, inheriting properties is generally undesirable; of course, - * it is always possible to change this behavior by calling {@link Mark#extend} - * explicitly. - * - * @param {function} type the type of the new mark to add. - * @returns {pv.Mark} the new mark. - */ -pv.Panel.prototype.add = function(type) { - var child = new type(); - child.parent = this; - child.root = this.root; - child.childIndex = this.children.length; - this.children.push(child); - return child; -}; - -/** @private TODO */ -pv.Panel.prototype.bind = function() { - pv.Mark.prototype.bind.call(this); - for (var i = 0; i < this.children.length; i++) { - this.children[i].bind(); - } -}; - -/** - * @private Evaluates all of the properties for this panel for the specified - * instance <tt>s</tt> in the scene graph, including recursively building the - * scene graph for child marks. - * - * @param s a node in the scene graph; the instance of the panel to build. - * @see Mark#scene - */ -pv.Panel.prototype.buildInstance = function(s) { - pv.Bar.prototype.buildInstance.call(this, s); - if (!s.children) s.children = []; - - /* - * Build each child, passing in the parent (this panel) scene graph node. The - * child mark's scene is initialized from the corresponding entry in the - * existing scene graph, such that properties from the previous build can be - * reused; this is largely to facilitate the recycling of SVG elements. - */ - for (var i = 0; i < this.children.length; i++) { - this.children[i].scene = s.children[i]; // possibly undefined - this.children[i].build(); - } - - /* - * Once the child marks have been built, the new scene graph nodes are removed - * from the child marks and placed into the scene graph. The nodes cannot - * remain on the child nodes because this panel (or a parent panel) may be - * instantiated multiple times! - */ - for (var i = 0; i < this.children.length; i++) { - s.children[i] = this.children[i].scene; - delete this.children[i].scene; - } - - /* Delete any expired child scenes, should child marks have been removed. */ - s.children.length = this.children.length; -}; - -/** - * @private Computes the implied properties for this panel for the specified - * instance <tt>s</tt> in the scene graph. Panels have two implied - * properties:<ul> - * - * <li>The <tt>canvas</tt> property references the DOM element, typically a DIV, - * that contains the SVG element that is used to display the visualization. This - * property may be specified as a string, referring to the unique ID of the - * element in the DOM. The string is converted to a reference to the DOM - * element. The width and height of the SVG element is inferred from this DOM - * element. If no canvas property is specified, a new SVG element is created and - * inserted into the document, using the panel dimensions; see - * {@link #createCanvas}. - * - * <li>The <tt>children</tt> array, while not a property per se, contains the - * scene graph for each child mark. This array is initialized to be empty, and - * is populated above in {@link #buildInstance}. - * - * </ul>The current implementation creates the SVG element, if necessary, during - * the build phase; in the future, it may be preferrable to move this to the - * update phase, although then the canvas property would be undefined. In - * addition, DOM inspection is necessary to define the implied width and height - * properties that may be inferred from the DOM. - * - * @param s a node in the scene graph; the instance of the panel to build. - */ -pv.Panel.prototype.buildImplied = function(s) { - if (!this.parent) { - var c = s.canvas; - if (c) { - if (typeof c == "string") c = document.getElementById(c); - - /* Clear the container if it's not associated with this panel. */ - if (c.$panel != this) { - c.$panel = this; - c.innerHTML = ""; - } - - /* If width and height weren't specified, inspect the container. */ - var w, h; - if (s.width == null) { - w = parseFloat(pv.css(c, "width")); - s.width = w - s.left - s.right; - } - if (s.height == null) { - h = parseFloat(pv.css(c, "height")); - s.height = h - s.top - s.bottom; - } - } else if (s.$canvas) { - - /* - * If the canvas property is null, and we previously created a canvas for - * this scene node, reuse the previous canvas rather than creating a new - * one. - */ - c = s.$canvas; - } else { - - /** - * Returns the last element in the current document's body. The canvas - * element is appended to this last element if another DOM element has not - * already been specified via the <tt>$dom</tt> field. - */ - function lastElement() { - var node = document.body; - while (node.lastChild && node.lastChild.tagName) { - node = node.lastChild; - } - return (node == document.body) ? node : node.parentNode; - } - - /* Insert a new container into the DOM. */ - c = s.$canvas = document.createElement("span"); - this.$dom // script element for text/javascript+protovis - ? this.$dom.parentNode.insertBefore(c, this.$dom) - : lastElement().appendChild(c); - } - s.canvas = c; - } - pv.Bar.prototype.buildImplied.call(this, s); -}; -/** - * Constructs a new dot mark with default properties. Images are not typically - * constructed directly, but by adding to a panel or an existing mark via - * {@link pv.Mark#add}. - * - * @class Represents an image. Images share the same layout and style properties as - * bars, in conjunction with an external image such as PNG or JPEG. The image is - * specified via the {@link #url} property. The fill, if specified, appears - * beneath the image, while the optional stroke appears above the image. - * - * <p>TODO Restore support for dynamic images (such as heatmaps). These were - * supported in the canvas implementation using the pixel buffer API; although - * SVG does not support pixel manipulation, it is possible to embed a canvas - * element in SVG using foreign objects. - * - * <p>TODO Allow different modes of image placement: "scale" -- scale and - * preserve aspect ratio, "tile" -- repeat the image, "center" -- center the - * image, "fill" -- scale without preserving aspect ratio. - * - * <p>See {@link pv.Bar} for details on positioning properties. - * - * @extends pv.Bar - */ -pv.Image = function() { - pv.Bar.call(this); -}; - -pv.Image.prototype = pv.extend(pv.Bar) - .property("url"); - -pv.Image.prototype.type = "image"; - -/** - * The URL of the image to display. The set of supported image types is - * browser-dependent; PNG and JPEG are recommended. - * - * @type string - * @name pv.Image.prototype.url - */ - -/** - * Default properties for images. By default, there is no stroke or fill style. - * - * @type pv.Image - */ -pv.Image.prototype.defaults = new pv.Image() - .extend(pv.Bar.prototype.defaults) - .fillStyle(null); -/** - * Constructs a new wedge with default properties. Wedges are not typically - * constructed directly, but by adding to a panel or an existing mark via - * {@link pv.Mark#add}. - * - * @class Represents a wedge, or pie slice. Specified in terms of start and end - * angle, inner and outer radius, wedges can be used to construct donut charts - * and polar bar charts as well. If the {@link #angle} property is used, the end - * angle is implied by adding this value to start angle. By default, the start - * angle is the previously-generated wedge's end angle. This design allows - * explicit control over the wedge placement if desired, while offering - * convenient defaults for the construction of radial graphs. - * - * <p>The center point of the circle is positioned using the standard box model. - * The wedge can be stroked and filled, similar to {link Bar}. - * - * <p>See also the <a href="../../api/Wedge.html">Wedge guide</a>. - * - * @extends pv.Mark - */ -pv.Wedge = function() { - pv.Mark.call(this); -}; - -pv.Wedge.prototype = pv.extend(pv.Mark) - .property("startAngle") - .property("endAngle") - .property("angle") - .property("innerRadius") - .property("outerRadius") - .property("lineWidth") - .property("strokeStyle") - .property("fillStyle"); - -pv.Wedge.prototype.type = "wedge"; - -/** - * The start angle of the wedge, in radians. The start angle is measured - * clockwise from the 3 o'clock position. The default value of this property is - * the end angle of the previous instance (the {@link Mark#sibling}), or -PI / 2 - * for the first wedge; for pie and donut charts, typically only the - * {@link #angle} property needs to be specified. - * - * @type number - * @name pv.Wedge.prototype.startAngle - */ - -/** - * The end angle of the wedge, in radians. If not specified, the end angle is - * implied as the start angle plus the {@link #angle}. - * - * @type number - * @name pv.Wedge.prototype.endAngle - */ - -/** - * The angular span of the wedge, in radians. This property is used if end angle - * is not specified. - * - * @type number - * @name pv.Wedge.prototype.angle - */ - -/** - * The inner radius of the wedge, in pixels. The default value of this property - * is zero; a positive value will produce a donut slice rather than a pie slice. - * The inner radius can vary per-wedge. - * - * @type number - * @name pv.Wedge.prototype.innerRadius - */ - -/** - * The outer radius of the wedge, in pixels. This property is required. For - * pies, only this radius is required; for donuts, the inner radius must be - * specified as well. The outer radius can vary per-wedge. - * - * @type number - * @name pv.Wedge.prototype.outerRadius - */ - -/** - * The width of stroked lines, in pixels; used in conjunction with - * <tt>strokeStyle</tt> to stroke the wedge's border. - * - * @type number - * @name pv.Wedge.prototype.lineWidth - */ - -/** - * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to - * stroke the wedge's border. The default value of this property is null, - * meaning wedges are not stroked by default. - * - * @type string - * @name pv.Wedge.prototype.strokeStyle - * @see pv.color - */ - -/** - * The wedge fill style; if non-null, the interior of the wedge is filled with - * the specified color. The default value of this property is a categorical - * color. - * - * @type string - * @name pv.Wedge.prototype.fillStyle - * @see pv.color - */ - -/** - * Default properties for wedges. By default, there is no stroke and the fill - * style is a categorical color. - * - * @type pv.Wedge - */ -pv.Wedge.prototype.defaults = new pv.Wedge() - .extend(pv.Mark.prototype.defaults) - .startAngle(function() { - var s = this.sibling(); - return s ? s.endAngle : -Math.PI / 2; - }) - .innerRadius(0) - .lineWidth(1.5) - .strokeStyle(null) - .fillStyle(defaultFillStyle.by(pv.index)); - -/** - * Returns the mid-radius of the wedge, which is defined as half-way between the - * inner and outer radii. - * - * @see #innerRadius - * @see #outerRadius - * @returns {number} the mid-radius, in pixels. - */ -pv.Wedge.prototype.midRadius = function() { - return (this.innerRadius() + this.outerRadius()) / 2; -}; - -/** - * Returns the mid-angle of the wedge, which is defined as half-way between the - * start and end angles. - * - * @see #startAngle - * @see #endAngle - * @returns {number} the mid-angle, in radians. - */ -pv.Wedge.prototype.midAngle = function() { - return (this.startAngle() + this.endAngle()) / 2; -}; - -/** - * Constructs a new wedge anchor with default properties. Wedges support five - * different anchors:<ul> - * - * <li>outer - * <li>inner - * <li>center - * <li>start - * <li>end - * - * </ul>In addition to positioning properties (left, right, top bottom), the - * anchors support text rendering properties (text-align, text-baseline, - * textAngle). Text is rendered to appear inside the wedge. - * - * @param {string} name the anchor name; either a string or a property function. - * @returns {pv.Anchor} - */ -pv.Wedge.prototype.anchor = function(name) { - var w = this; - return pv.Mark.prototype.anchor.call(this, name) - .left(function() { - switch (this.name()) { - case "outer": return w.left() + w.outerRadius() * Math.cos(w.midAngle()); - case "inner": return w.left() + w.innerRadius() * Math.cos(w.midAngle()); - case "start": return w.left() + w.midRadius() * Math.cos(w.startAngle()); - case "center": return w.left() + w.midRadius() * Math.cos(w.midAngle()); - case "end": return w.left() + w.midRadius() * Math.cos(w.endAngle()); - } - }) - .right(function() { - switch (this.name()) { - case "outer": return w.right() + w.outerRadius() * Math.cos(w.midAngle()); - case "inner": return w.right() + w.innerRadius() * Math.cos(w.midAngle()); - case "start": return w.right() + w.midRadius() * Math.cos(w.startAngle()); - case "center": return w.right() + w.midRadius() * Math.cos(w.midAngle()); - case "end": return w.right() + w.midRadius() * Math.cos(w.endAngle()); - } - }) - .top(function() { - switch (this.name()) { - case "outer": return w.top() + w.outerRadius() * Math.sin(w.midAngle()); - case "inner": return w.top() + w.innerRadius() * Math.sin(w.midAngle()); - case "start": return w.top() + w.midRadius() * Math.sin(w.startAngle()); - case "center": return w.top() + w.midRadius() * Math.sin(w.midAngle()); - case "end": return w.top() + w.midRadius() * Math.sin(w.endAngle()); - } - }) - .bottom(function() { - switch (this.name()) { - case "outer": return w.bottom() + w.outerRadius() * Math.sin(w.midAngle()); - case "inner": return w.bottom() + w.innerRadius() * Math.sin(w.midAngle()); - case "start": return w.bottom() + w.midRadius() * Math.sin(w.startAngle()); - case "center": return w.bottom() + w.midRadius() * Math.sin(w.midAngle()); - case "end": return w.bottom() + w.midRadius() * Math.sin(w.endAngle()); - } - }) - .textAlign(function() { - switch (this.name()) { - case "outer": return pv.Wedge.upright(w.midAngle()) ? "right" : "left"; - case "inner": return pv.Wedge.upright(w.midAngle()) ? "left" : "right"; - } - return "center"; - }) - .textBaseline(function() { - switch (this.name()) { - case "start": return pv.Wedge.upright(w.startAngle()) ? "top" : "bottom"; - case "end": return pv.Wedge.upright(w.endAngle()) ? "bottom" : "top"; - } - return "middle"; - }) - .textAngle(function() { - var a = 0; - switch (this.name()) { - case "center": - case "inner": - case "outer": a = w.midAngle(); break; - case "start": a = w.startAngle(); break; - case "end": a = w.endAngle(); break; - } - return pv.Wedge.upright(a) ? a : (a + Math.PI); - }); -}; - -/** - * Returns true if the specified angle is considered "upright", as in, text - * rendered at that angle would appear upright. If the angle is not upright, - * text is rotated 180 degrees to be upright, and the text alignment properties - * are correspondingly changed. - * - * @param {number} angle an angle, in radius. - * @returns {boolean} true if the specified angle is upright. - */ -pv.Wedge.upright = function(angle) { - angle = angle % (2 * Math.PI); - angle = (angle < 0) ? (2 * Math.PI + angle) : angle; - return (angle < Math.PI / 2) || (angle > 3 * Math.PI / 2); -}; - -/** - * @private Overrides the default behavior of {@link pv.Mark.buildImplied} such - * that the end angle is computed from the start angle and angle (angular span) - * if not specified. - * - * @param s a node in the scene graph; the instance of the wedge to build. - */ -pv.Wedge.prototype.buildImplied = function(s) { - pv.Mark.prototype.buildImplied.call(this, s); - - /* - * TODO If the angle or endAngle is updated by an event handler, the implied - * properties won't recompute correctly, so this will lead to potentially - * buggy redraw. How to re-evaluate implied properties on update? - */ - if (s.endAngle == null) s.endAngle = s.startAngle + s.angle; - if (s.angle == null) s.angle = s.endAngle - s.startAngle; -}; -/** - * @ignore - * @namespace - */ -pv.Layout = {}; -/** - * Returns a new grid layout. - * - * @class A grid layout with regularly-sized rows and columns. <img - * src="../grid.png" width="160" height="160" align="right"> The number of rows - * and columns are determined from the array, which should be in row-major - * order. For example, the 2×3 array: - * - * <pre>1 2 3 - * 4 5 6</pre> - * - * should be represented as: - * - * <pre>[[1, 2, 3], [4, 5, 6]]</pre> - * - * If your data is in column-major order, you can use {@link pv.transpose} to - * transpose it. - * - * <p>This layout defines left, top, width, height and data properties. The data - * property will be the associated element in the array. For example, if the - * array is a two-dimensional array of values in the range [0,1], a simple - * heatmap can be generated as: - * - * <pre>.add(pv.Bar) - * .extend(pv.Layout.grid(array)) - * .fillStyle(pv.ramp("white", "black"))</pre> - * - * By default, the grid fills the full width and height of the parent panel. - * - * @param {array[]} arrays an array of arrays. - * @returns {pv.Layout.grid} a grid layout. - */ -pv.Layout.grid = function(arrays) { - var rows = arrays.length, cols = arrays[0].length; - - /** @private */ - function w() { return this.parent.width() / cols; } - - /** @private */ - function h() { return this.parent.height() / rows; } - - /* A dummy mark, like an anchor, which the caller extends. */ - return new pv.Mark() - .data(pv.blend(arrays)) - .left(function() { return w.call(this) * (this.index % cols); }) - .top(function() { return h.call(this) * Math.floor(this.index / cols); }) - .width(w) - .height(h); -}; -/** - * Returns a new stack layout. - * - * @class A layout for stacking marks vertically or horizontally, using the - * <i>cousin</i> instance. This layout is designed to be used for one of the - * four positional properties in the box model, and changes behavior depending - * on the property being evaluated:<ul> - * - * <li>bottom: cousin.bottom + cousin.height - * <li>top: cousin.top + cousin.height - * <li>left: cousin.left + cousin.width - * <li>right: cousin.right + cousin.width - * - * </ul>If no cousin instance is available (for example, for first instance), - * the specified offset is used. If no offset is specified, zero is used. For - * example, - * - * <pre>new pv.Panel() - * .width(150).height(150) - * .add(pv.Panel) - * .data([[1, 1.2, 1.7, 1.5, 1.7], - * [.5, 1, .8, 1.1, 1.3], - * [.2, .5, .8, .9, 1]]) - * .add(pv.Area) - * .data(function(d) d) - * .bottom(pv.Layout.stack()) - * .height(function(d) d * 40) - * .left(function() this.index * 35) - * .root.render();</pre> - * - * specifies a vertically-stacked area chart. - * - * @returns {pv.Layout.stack} a stack property function. - * @see pv.Mark#cousin - */ -pv.Layout.stack = function() { - /** @private */ - var offset = function() { return 0; }; - - /** @private */ - function layout() { - - /* Find the previous visible parent instance. */ - var i = this.parent.index, p, c; - while ((i-- > 0) && !c) { - p = this.parent.scene[i]; - if (p.visible) c = p.children[this.childIndex][this.index]; - } - - if (c) { - switch (property) { - case "bottom": return c.bottom + c.height; - case "top": return c.top + c.height; - case "left": return c.left + c.width; - case "right": return c.right + c.width; - } - } - - return offset.apply(this, arguments); - } - - /** - * Sets the offset for this stack layout. The offset can either be specified - * as a function or as a constant. If a function, the function is invoked in - * the same context as a normal property function: <tt>this</tt> refers to the - * mark, and the arguments are the full data stack. By default the offset is - * zero. - * - * @function - * @name pv.Layout.stack.prototype.offset - * @param {function} f offset function, or constant value. - * @returns {pv.Layout.stack} this. - */ - layout.offset = function(f) { - offset = (f instanceof Function) ? f : function() { return f; }; - return this; - }; - - return layout; -}; -// TODO share code with Treemap -// TODO vertical / horizontal orientation? - -/** - * Returns a new icicle tree layout. - * - * @class A tree layout in the form of an icicle. <img src="../icicle.png" - * width="160" height="160" align="right"> The first row corresponds to the root - * of the tree; subsequent rows correspond to each tier. Rows are subdivided - * into cells based on the size of nodes, per {@link #size}. Within a row, cells - * are sorted by size. - * - * <p>This tree layout is intended to be extended (see {@link pv.Mark#extend}) - * by a {@link pv.Bar}. The data property returns an array of nodes for use by - * other property functions. The following node attributes are supported: - * - * <ul> - * <li><tt>left</tt> - the cell left position. - * <li><tt>top</tt> - the cell top position. - * <li><tt>width</tt> - the cell width. - * <li><tt>height</tt> - the cell height. - * <li><tt>depth</tt> - the node depth (tier; the root is 0). - * <li><tt>keys</tt> - an array of string keys for the node. - * <li><tt>size</tt> - the aggregate node size. - * <li><tt>children</tt> - child nodes, if any. - * <li><tt>data</tt> - the associated tree element, for leaf nodes. - * </ul> - * - * To produce a default icicle layout, say: - * - * <pre>.add(pv.Bar) - * .extend(pv.Layout.icicle(tree))</pre> - * - * To customize the tree to highlight leaf nodes bigger than 10,000 (1E4), you - * might say: - * - * <pre>.add(pv.Bar) - * .extend(pv.Layout.icicle(tree)) - * .fillStyle(function(n) n.data > 1e4 ? "#ff0" : "#fff")</pre> - * - * The format of the <tt>tree</tt> argument is any hierarchical object whose - * leaf nodes are numbers corresponding to their size. For an example, and - * information on how to convert tabular data into such a tree, see - * {@link pv.Tree}. If the leaf nodes are not numbers, a {@link #size} function - * can be specified to override how the tree is interpreted. This size function - * can also be used to transform the data. - * - * <p>By default, the icicle fills the full width and height of the parent - * panel. An optional root key can be specified using {@link #root} for - * convenience. - * - * @param tree a tree (an object) who leaf attributes have sizes. - * @returns {pv.Layout.icicle} a tree layout. - */ -pv.Layout.icicle = function(tree) { - var keys = [], sizeof = Number; - - /** @private */ - function accumulate(map) { - var node = {size: 0, children: [], keys: keys.slice()}; - for (var key in map) { - var child = map[key], size = sizeof(child); - keys.push(key); - if (isNaN(size)) { - child = accumulate(child); - } else { - child = {size: size, data: child, keys: keys.slice()}; - } - node.children.push(child); - node.size += child.size; - keys.pop(); - } - node.children.sort(function(a, b) { return b.size - a.size; }); - return node; - } - - /** @private */ - function scale(node, k) { - node.size *= k; - if (node.children) { - for (var i = 0; i < node.children.length; i++) { - scale(node.children[i], k); - } - } - } - - /** @private */ - function depth(node, i) { - i = i ? (i + 1) : 1; - return node.children - ? pv.max(node.children, function(n) { return depth(n, i); }) - : i; - } - - /** @private */ - function layout(node) { - if (node.children) { - icify(node); - for (var i = 0; i < node.children.length; i++) { - layout(node.children[i]); - } - } - } - - /** @private */ - function icify(node) { - var left = node.left; - for (var i = 0; i < node.children.length; i++) { - var child = node.children[i], width = (child.size / node.size) * node.width; - child.left = left; - child.top = node.top + node.height; - child.width = width; - child.height = node.height; - child.depth = node.depth + 1; - left += width; - if (child.children) { - icify(child); - } - } - } - - /** @private */ - function flatten(node, array) { - if (node.children) { - for (var i = 0; i < node.children.length; i++) { - flatten(node.children[i], array); - } - } - array.push(node) - return array; - } - - /** @private */ - function data() { - var root = accumulate(tree); - root.top = 0; - root.left = 0; - root.width = this.parent.width(); - root.height = this.parent.height() / depth(root); - root.depth = 0; - layout(root); - return flatten(root, []).reverse(); - } - - /* A dummy mark, like an anchor, which the caller extends. */ - var mark = new pv.Mark() - .data(data) - .left(function(n) { return n.left; }) - .top(function(n) { return n.top; }) - .width(function(n) { return n.width; }) - .height(function(n) { return n.height; }); - - /** - * Specifies the root key; optional. The root key is prepended to the - * <tt>keys</tt> attribute for all generated nodes. This method is provided - * for convenience and does not affect layout. - * - * @param {string} v the root key. - * @function - * @name pv.Layout.icicle.prototype.root - * @returns {pv.Layout.icicle} this. - */ - mark.root = function(v) { - keys = [v]; - return this; - }; - - /** - * Specifies the sizing function. By default, the sizing function is - * <tt>Number</tt>. The sizing function is invoked for each node in the tree - * (passed to the constructor): the sizing function must return - * <tt>undefined</tt> or <tt>NaN</tt> for internal nodes, and a number for - * leaf nodes. The aggregate sizes of internal nodes will be automatically - * computed by the layout. - * - * <p>For example, if the tree data structure represents a file system, with - * files as leaf nodes, and each file has a <tt>bytes</tt> attribute, you can - * specify a size function as: - * - * <pre>.size(function(d) d.bytes)</pre> - * - * This function will return <tt>undefined</tt> for internal nodes (since - * these do not have a <tt>bytes</tt> attribute), and a number for leaf nodes. - * - * <p>Note that the built-in <tt>Math.sqrt</tt> and <tt>Math.log</tt> methods - * can also be used as sizing functions. These function similarly to - * <tt>Number</tt>, except perform a root and log scale, respectively. - * - * @param {function} f the new sizing function. - * @function - * @name pv.Layout.icicle.prototype.size - * @returns {pv.Layout.icicle} this. - */ - mark.size = function(f) { - sizeof = f; - return this; - }; - - return mark; -}; -// TODO share code with Treemap -// TODO inspect parent panel dimensions to set inner and outer radii - -/** - * Returns a new sunburst tree layout. - * - * @class A tree layout in the form of a sunburst. <img - * src="../sunburst.png" width="160" height="160" align="right"> The - * center circle corresponds to the root of the tree; subsequent rings - * correspond to each tier. Rings are subdivided into wedges based on the size - * of nodes, per {@link #size}. Within a ring, wedges are sorted by size. - * - * <p>The tree layout is intended to be extended (see {@link pv.Mark#extend} by - * a {@link pv.Wedge}. The data property returns an array of nodes for use by - * other property functions. The following node attributes are supported: - * - * <ul> - * <li><tt>left</tt> - the wedge left position. - * <li><tt>top</tt> - the wedge top position. - * <li><tt>innerRadius</tt> - the wedge inner radius. - * <li><tt>outerRadius</tt> - the wedge outer radius. - * <li><tt>startAngle</tt> - the wedge start angle. - * <li><tt>endAngle</tt> - the wedge end angle. - * <li><tt>angle</tt> - the wedge angle. - * <li><tt>depth</tt> - the node depth (tier; the root is 0). - * <li><tt>keys</tt> - an array of string keys for the node. - * <li><tt>size</tt> - the aggregate node size. - * <li><tt>children</tt> - child nodes, if any. - * <li><tt>data</tt> - the associated tree element, for leaf nodes. - * </ul> - * - * <p>To produce a default sunburst layout, say: - * - * <pre>.add(pv.Wedge) - * .extend(pv.Layout.sunburst(tree))</pre> - * - * To only show nodes at a depth of two or greater, you might say: - * - * <pre>.add(pv.Wedge) - * .extend(pv.Layout.sunburst(tree)) - * .visible(function(n) n.depth > 1)</pre> - * - * The format of the <tt>tree</tt> argument is a hierarchical object whose leaf - * nodes are numbers corresponding to their size. For an example, and - * information on how to convert tabular data into such a tree, see - * {@link pv.Tree}. If the leaf nodes are not numbers, a {@link #size} function - * can be specified to override how the tree is interpreted. This size function - * can also be used to transform the data. - * - * <p>By default, the sunburst fills the full width and height of the parent - * panel. An optional root key can be specified using {@link #root} for - * convenience. - * - * @param tree a tree (an object) who leaf attributes have sizes. - * @returns {pv.Layout.sunburst} a tree layout. - */ -pv.Layout.sunburst = function(tree) { - var keys = [], sizeof = Number, w, h, r; - - /** @private */ - function accumulate(map) { - var node = {size: 0, children: [], keys: keys.slice()}; - for (var key in map) { - var child = map[key], size = sizeof(child); - keys.push(key); - if (isNaN(size)) { - child = accumulate(child); - } else { - child = {size: size, data: child, keys: keys.slice()}; - } - node.children.push(child); - node.size += child.size; - keys.pop(); - } - node.children.sort(function(a, b) { return b.size - a.size; }); - return node; - } - - /** @private */ - function scale(node, k) { - node.size *= k; - if (node.children) { - for (var i = 0; i < node.children.length; i++) { - scale(node.children[i], k); - } - } - } - - /** @private */ - function depth(node, i) { - i = i ? (i + 1) : 1; - return node.children - ? pv.max(node.children, function(n) { return depth(n, i); }) - : i; - } - - /** @private */ - function layout(node) { - if (node.children) { - wedgify(node); - for (var i = 0; i < node.children.length; i++) { - layout(node.children[i]); - } - } - } - - /** @private */ - function wedgify(node) { - var startAngle = node.startAngle; - for (var i = 0; i < node.children.length; i++) { - var child = node.children[i], angle = (child.size / node.size) * node.angle; - child.startAngle = startAngle; - child.angle = angle; - child.endAngle = startAngle + angle; - child.depth = node.depth + 1; - child.left = w / 2; - child.top = h / 2; - child.innerRadius = Math.max(0, child.depth - .5) * r; - child.outerRadius = (child.depth + .5) * r; - startAngle += angle; - if (child.children) { - wedgify(child); - } - } - } - - /** @private */ - function flatten(node, array) { - if (node.children) { - for (var i = 0; i < node.children.length; i++) { - flatten(node.children[i], array); - } - } - array.push(node) - return array; - } - - /** @private */ - function data() { - var root = accumulate(tree); - w = this.parent.width(); - h = this.parent.height(); - r = Math.min(w, h) / 2 / (depth(root) - .5); - root.left = w / 2; - root.top = h / 2; - root.startAngle = 0; - root.angle = 2 * Math.PI; - root.endAngle = 2 * Math.PI; - root.innerRadius = 0; - root.outerRadius = r; - root.depth = 0; - layout(root); - return flatten(root, []).reverse(); - } - - /* A dummy mark, like an anchor, which the caller extends. */ - var mark = new pv.Mark() - .data(data) - .left(function(n) { return n.left; }) - .top(function(n) { return n.top; }) - .startAngle(function(n) { return n.startAngle; }) - .angle(function(n) { return n.angle; }) - .innerRadius(function(n) { return n.innerRadius; }) - .outerRadius(function(n) { return n.outerRadius; }); - - /** - * Specifies the root key; optional. The root key is prepended to the - * <tt>keys</tt> attribute for all generated nodes. This method is provided - * for convenience and does not affect layout. - * - * @param {string} v the root key. - * @function - * @name pv.Layout.sunburst.prototype.root - * @returns {pv.Layout.sunburst} this. - */ - mark.root = function(v) { - keys = [v]; - return this; - }; - - /** - * Specifies the sizing function. By default, the sizing function is - * <tt>Number</tt>. The sizing function is invoked for each node in the tree - * (passed to the constructor): the sizing function must return - * <tt>undefined</tt> or <tt>NaN</tt> for internal nodes, and a number for - * leaf nodes. The aggregate sizes of internal nodes will be automatically - * computed by the layout. - * - * <p>For example, if the tree data structure represents a file system, with - * files as leaf nodes, and each file has a <tt>bytes</tt> attribute, you can - * specify a size function as: - * - * <pre>.size(function(d) d.bytes)</pre> - * - * This function will return <tt>undefined</tt> for internal nodes (since - * these do not have a <tt>bytes</tt> attribute), and a number for leaf nodes. - * - * <p>Note that the built-in <tt>Math.sqrt</tt> and <tt>Math.log</tt> methods - * can be used as sizing functions. These function similarly to - * <tt>Number</tt>, except perform a root and log scale, respectively. - * - * @param {function} f the new sizing function. - * @function - * @name pv.Layout.sunburst.prototype.size - * @returns {pv.Layout.sunburst} this. - */ - mark.size = function(f) { - sizeof = f; - return this; - }; - - return mark; -}; -// TODO add `by` function for determining size (and children?) - -/** - * Returns a new treemap tree layout. - * - * @class A tree layout in the form of an treemap. <img - * src="../treemap.png" width="160" height="160" align="right"> Treemaps - * are a form of space-filling layout that represents nodes as boxes, with child - * nodes placed within parent boxes. The size of each box is proportional to the - * size of the node in the tree. - * - * <p>This particular algorithm is taken from Bruls, D.M., C. Huizing, and - * J.J. van Wijk, <a href="http://www.win.tue.nl/~vanwijk/stm.pdf">"Squarified - * Treemaps"</a> in <i>Data Visualization 2000, Proceedings of the Joint - * Eurographics and IEEE TCVG Sumposium on Visualization</i>, 2000, - * pp. 33-42. - * - * <p>This tree layout is intended to be extended (see {@link pv.Mark#extend}) - * by a {@link pv.Bar}. The data property returns an array of nodes for use by - * other property functions. The following node attributes are supported: - * - * <ul> - * <li><tt>left</tt> - the cell left position. - * <li><tt>top</tt> - the cell top position. - * <li><tt>width</tt> - the cell width. - * <li><tt>height</tt> - the cell height. - * <li><tt>depth</tt> - the node depth (tier; the root is 0). - * <li><tt>keys</tt> - an array of string keys for the node. - * <li><tt>size</tt> - the aggregate node size. - * <li><tt>children</tt> - child nodes, if any. - * <li><tt>data</tt> - the associated tree element, for leaf nodes. - * </ul> - * - * To produce a default treemap layout, say: - * - * <pre>.add(pv.Bar) - * .extend(pv.Layout.treemap(tree))</pre> - * - * To display internal nodes, and color by depth, say: - * - * <pre>.add(pv.Bar) - * .extend(pv.Layout.treemap(tree).inset(10)) - * .fillStyle(pv.Colors.category19().by(function(n) n.depth))</pre> - * - * The format of the <tt>tree</tt> argument is a hierarchical object whose leaf - * nodes are numbers corresponding to their size. For an example, and - * information on how to convert tabular data into such a tree, see - * {@link pv.Tree}. If the leaf nodes are not numbers, a {@link #size} function - * can be specified to override how the tree is interpreted. This size function - * can also be used to transform the data. - * - * <p>By default, the treemap fills the full width and height of the parent - * panel, and only leaf nodes are rendered. If an {@link #inset} is specified, - * internal nodes will be rendered, each inset from their parent by the - * specified margins. Rounding can be enabled using {@link #round}. Finally, an - * optional root key can be specified using {@link #root} for convenience. - * - * @param tree a tree (an object) who leaf attributes have sizes. - * @returns {pv.Layout.treemap} a tree layout. - */ -pv.Layout.treemap = function(tree) { - var keys = [], round, inset, sizeof = Number; - - /** @private */ - function rnd(i) { - return round ? Math.round(i) : i; - } - - /** @private */ - function accumulate(map) { - var node = {size: 0, children: [], keys: keys.slice()}; - for (var key in map) { - var child = map[key], size = sizeof(child); - keys.push(key); - if (isNaN(size)) { - child = accumulate(child); - } else { - child = {size: size, data: child, keys: keys.slice()}; - } - node.children.push(child); - node.size += child.size; - keys.pop(); - } - node.children.sort(function(a, b) { return a.size - b.size; }); - return node; - } - - /** @private */ - function scale(node, k) { - node.size *= k; - if (node.children) { - for (var i = 0; i < node.children.length; i++) { - scale(node.children[i], k); - } - } - } - - /** @private */ - function ratio(row, l) { - var rmax = -Infinity, rmin = Infinity, s = 0; - for (var i = 0; i < row.length; i++) { - var r = row[i].size; - if (r < rmin) rmin = r; - if (r > rmax) rmax = r; - s += r; - } - s = s * s; - l = l * l; - return Math.max(l * rmax / s, s / (l * rmin)); - } - - /** @private */ - function squarify(node) { - var row = [], mink = Infinity; - var x = node.left + (inset ? inset.left : 0), - y = node.top + (inset ? inset.top : 0), - w = node.width - (inset ? inset.left + inset.right : 0), - h = node.height - (inset ? inset.top + inset.bottom : 0), - l = Math.min(w, h); - - scale(node, w * h / node.size); - - function position(row) { - var s = pv.sum(row, function(node) { return node.size; }), - hh = (l == 0) ? 0 : rnd(s / l); - - for (var i = 0, d = 0; i < row.length; i++) { - var n = row[i], nw = rnd(n.size / hh); - if (w == l) { - n.left = x + d; - n.top = y; - n.width = nw; - n.height = hh; - } else { - n.left = x; - n.top = y + d; - n.width = hh; - n.height = nw; - } - d += nw; - } - - if (w == l) { - if (n) n.width += w - d; // correct rounding error - y += hh; - h -= hh; - } else { - if (n) n.height += h - d; // correct rounding error - x += hh; - w -= hh; - } - l = Math.min(w, h); - } - - var children = node.children.slice(); // copy - while (children.length > 0) { - var child = children[children.length - 1]; - if (child.size <= 0) { - children.pop(); - continue; - } - row.push(child); - - var k = ratio(row, l); - if (k <= mink) { - children.pop(); - mink = k; - } else { - row.pop(); - position(row); - row.length = 0; - mink = Infinity; - } - } - - if (row.length > 0) { - position(row); - } - - /* correct rounding error */ - if (w == l) { - for (var i = 0; i < row.length; i++) { - row[i].width += w; - } - } else { - for (var i = 0; i < row.length; i++) { - row[i].height += h; - } - } - } - - /** @private */ - function layout(node) { - if (node.children) { - squarify(node); - for (var i = 0; i < node.children.length; i++) { - var child = node.children[i]; - child.depth = node.depth + 1; - layout(child); - } - } - } - - /** @private */ - function flatten(node, array) { - if (node.children) { - for (var i = 0; i < node.children.length; i++) { - flatten(node.children[i], array); - } - } - if (inset || !node.children) { - array.push(node) - } - return array; - } - - /** @private */ - function data() { - var root = accumulate(tree); - root.left = 0; - root.top = 0; - root.width = this.parent.width(); - root.height = this.parent.height(); - root.depth = 0; - layout(root); - return flatten(root, []).reverse(); - } - - /* A dummy mark, like an anchor, which the caller extends. */ - var mark = new pv.Mark() - .data(data) - .left(function(n) { return n.left; }) - .top(function(n) { return n.top; }) - .width(function(n) { return n.width; }) - .height(function(n) { return n.height; }); - - /** - * Enables or disables rounding. When rounding is enabled, the left, top, - * width and height properties will be rounded to integer pixel values. The - * rounding algorithm uses error accumulation to ensure an exact fit. - * - * @param {boolean} v whether rounding should be enabled. - * @function - * @name pv.Layout.treemap.prototype.round - * @returns {pv.Layout.treemap} this. - */ - mark.round = function(v) { - round = v; - return this; - }; - - /** - * Specifies the margins to inset child nodes from their parents; as a side - * effect, this also enables the display of internal nodes, which are hidden - * by default. If only a single argument is specified, this value is used to - * inset all four sides. - * - * @param {number} top the top margin. - * @param {number} [right] the right margin. - * @param {number} [bottom] the bottom margin. - * @param {number} [left] the left margin. - * @function - * @name pv.Layout.treemap.prototype.inset - * @returns {pv.Layout.treemap} this. - */ - mark.inset = function(top, right, bottom, left) { - if (arguments.length == 1) right = bottom = left = top; - inset = {top:top, right:right, bottom:bottom, left:left}; - return this; - }; - - /** - * Specifies the root key; optional. The root key is prepended to the - * <tt>keys</tt> attribute for all generated nodes. This method is provided - * for convenience and does not affect layout. - * - * @param {string} v the root key. - * @function - * @name pv.Layout.treemap.prototype.root - * @returns {pv.Layout.treemap} this. - */ - mark.root = function(v) { - keys = [v]; - return this; - }; - - /** - * Specifies the sizing function. By default, the sizing function is - * <tt>Number</tt>. The sizing function is invoked for each node in the tree - * (passed to the constructor): the sizing function must return - * <tt>undefined</tt> or <tt>NaN</tt> for internal nodes, and a number for - * leaf nodes. The aggregate sizes of internal nodes will be automatically - * computed by the layout. - * - * <p>For example, if the tree data structure represents a file system, with - * files as leaf nodes, and each file has a <tt>bytes</tt> attribute, you can - * specify a size function as: - * - * <pre>.size(function(d) d.bytes)</pre> - * - * This function will return <tt>undefined</tt> for internal nodes (since - * these do not have a <tt>bytes</tt> attribute), and a number for leaf nodes. - * - * <p>Note that the built-in <tt>Math.sqrt</tt> and <tt>Math.log</tt> methods - * can be used as sizing functions. These function similarly to - * <tt>Number</tt>, except perform a root and log scale, respectively. - * - * @param {function} f the new sizing function. - * @function - * @name pv.Layout.treemap.prototype.size - * @returns {pv.Layout.treemap} this. - */ - mark.size = function(f) { - sizeof = f; - return this; - }; - - return mark; -}; - return pv;}();/* - * Parses the Protovis specifications on load, allowing the use of JavaScript - * 1.8 function expressions on browsers that only support JavaScript 1.6. - * - * @see pv.parse - */ -pv.listen(window, "load", function() { - var scripts = document.getElementsByTagName("script"); - for (var i = 0; i < scripts.length; i++) { - var s = scripts[i]; - if (s.type == "text/javascript+protovis") { - try { - pv.Panel.$dom = s; - window.eval(pv.parse(s.textContent || s.innerHTML)); // IE - } catch (e) { - pv.error(e); - } - delete pv.Panel.$dom; - } - } - }); |