From 823344c19094680e80e2b56449a243e183db8b06 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Mon, 14 Dec 2020 23:21:39 -0800 Subject: :star: --- semantic/src/definitions/modules/accordion.js | 618 ++++ semantic/src/definitions/modules/accordion.less | 219 ++ semantic/src/definitions/modules/calendar.js | 1774 +++++++++ semantic/src/definitions/modules/calendar.less | 195 + semantic/src/definitions/modules/checkbox.js | 876 +++++ semantic/src/definitions/modules/checkbox.less | 814 +++++ semantic/src/definitions/modules/dimmer.js | 753 ++++ semantic/src/definitions/modules/dimmer.less | 390 ++ semantic/src/definitions/modules/dropdown.js | 4238 ++++++++++++++++++++++ semantic/src/definitions/modules/dropdown.less | 1850 ++++++++++ semantic/src/definitions/modules/embed.js | 709 ++++ semantic/src/definitions/modules/embed.less | 160 + semantic/src/definitions/modules/modal.js | 1209 ++++++ semantic/src/definitions/modules/modal.less | 583 +++ semantic/src/definitions/modules/nag.js | 492 +++ semantic/src/definitions/modules/nag.less | 158 + semantic/src/definitions/modules/popup.js | 1541 ++++++++ semantic/src/definitions/modules/popup.less | 841 +++++ semantic/src/definitions/modules/progress.js | 1035 ++++++ semantic/src/definitions/modules/progress.less | 618 ++++ semantic/src/definitions/modules/rating.js | 554 +++ semantic/src/definitions/modules/rating.less | 177 + semantic/src/definitions/modules/search.js | 1565 ++++++++ semantic/src/definitions/modules/search.less | 560 +++ semantic/src/definitions/modules/shape.js | 848 +++++ semantic/src/definitions/modules/shape.less | 155 + semantic/src/definitions/modules/sidebar.js | 1036 ++++++ semantic/src/definitions/modules/sidebar.less | 654 ++++ semantic/src/definitions/modules/slider.js | 1314 +++++++ semantic/src/definitions/modules/slider.less | 417 +++ semantic/src/definitions/modules/sticky.js | 957 +++++ semantic/src/definitions/modules/sticky.less | 74 + semantic/src/definitions/modules/tab.js | 1001 +++++ semantic/src/definitions/modules/tab.less | 91 + semantic/src/definitions/modules/toast.js | 872 +++++ semantic/src/definitions/modules/toast.less | 590 +++ semantic/src/definitions/modules/transition.js | 1109 ++++++ semantic/src/definitions/modules/transition.less | 82 + 38 files changed, 31129 insertions(+) create mode 100644 semantic/src/definitions/modules/accordion.js create mode 100644 semantic/src/definitions/modules/accordion.less create mode 100644 semantic/src/definitions/modules/calendar.js create mode 100644 semantic/src/definitions/modules/calendar.less create mode 100644 semantic/src/definitions/modules/checkbox.js create mode 100644 semantic/src/definitions/modules/checkbox.less create mode 100644 semantic/src/definitions/modules/dimmer.js create mode 100644 semantic/src/definitions/modules/dimmer.less create mode 100644 semantic/src/definitions/modules/dropdown.js create mode 100644 semantic/src/definitions/modules/dropdown.less create mode 100644 semantic/src/definitions/modules/embed.js create mode 100644 semantic/src/definitions/modules/embed.less create mode 100644 semantic/src/definitions/modules/modal.js create mode 100644 semantic/src/definitions/modules/modal.less create mode 100644 semantic/src/definitions/modules/nag.js create mode 100644 semantic/src/definitions/modules/nag.less create mode 100644 semantic/src/definitions/modules/popup.js create mode 100644 semantic/src/definitions/modules/popup.less create mode 100644 semantic/src/definitions/modules/progress.js create mode 100644 semantic/src/definitions/modules/progress.less create mode 100644 semantic/src/definitions/modules/rating.js create mode 100644 semantic/src/definitions/modules/rating.less create mode 100644 semantic/src/definitions/modules/search.js create mode 100644 semantic/src/definitions/modules/search.less create mode 100644 semantic/src/definitions/modules/shape.js create mode 100644 semantic/src/definitions/modules/shape.less create mode 100644 semantic/src/definitions/modules/sidebar.js create mode 100644 semantic/src/definitions/modules/sidebar.less create mode 100644 semantic/src/definitions/modules/slider.js create mode 100644 semantic/src/definitions/modules/slider.less create mode 100644 semantic/src/definitions/modules/sticky.js create mode 100644 semantic/src/definitions/modules/sticky.less create mode 100644 semantic/src/definitions/modules/tab.js create mode 100644 semantic/src/definitions/modules/tab.less create mode 100644 semantic/src/definitions/modules/toast.js create mode 100644 semantic/src/definitions/modules/toast.less create mode 100644 semantic/src/definitions/modules/transition.js create mode 100644 semantic/src/definitions/modules/transition.less (limited to 'semantic/src/definitions/modules') diff --git a/semantic/src/definitions/modules/accordion.js b/semantic/src/definitions/modules/accordion.js new file mode 100644 index 0000000..392d498 --- /dev/null +++ b/semantic/src/definitions/modules/accordion.js @@ -0,0 +1,618 @@ +/*! + * # Fomantic-UI - Accordion + * http://github.com/fomantic/Fomantic-UI/ + * + * + * Released under the MIT license + * http://opensource.org/licenses/MIT + * + */ + +;(function ($, window, document, undefined) { + +'use strict'; + +$.isFunction = $.isFunction || function(obj) { + return typeof obj === "function" && typeof obj.nodeType !== "number"; +}; + +window = (typeof window != 'undefined' && window.Math == Math) + ? window + : (typeof self != 'undefined' && self.Math == Math) + ? self + : Function('return this')() +; + +$.fn.accordion = function(parameters) { + var + $allModules = $(this), + + time = new Date().getTime(), + performance = [], + + query = arguments[0], + methodInvoked = (typeof query == 'string'), + queryArguments = [].slice.call(arguments, 1), + + returnedValue + ; + $allModules + .each(function() { + var + settings = ( $.isPlainObject(parameters) ) + ? $.extend(true, {}, $.fn.accordion.settings, parameters) + : $.extend({}, $.fn.accordion.settings), + + className = settings.className, + namespace = settings.namespace, + selector = settings.selector, + error = settings.error, + + eventNamespace = '.' + namespace, + moduleNamespace = 'module-' + namespace, + moduleSelector = $allModules.selector || '', + + $module = $(this), + $title = $module.find(selector.title), + $content = $module.find(selector.content), + + element = this, + instance = $module.data(moduleNamespace), + observer, + module + ; + + module = { + + initialize: function() { + module.debug('Initializing', $module); + module.bind.events(); + if(settings.observeChanges) { + module.observeChanges(); + } + module.instantiate(); + }, + + instantiate: function() { + instance = module; + $module + .data(moduleNamespace, module) + ; + }, + + destroy: function() { + module.debug('Destroying previous instance', $module); + $module + .off(eventNamespace) + .removeData(moduleNamespace) + ; + }, + + refresh: function() { + $title = $module.find(selector.title); + $content = $module.find(selector.content); + }, + + observeChanges: function() { + if('MutationObserver' in window) { + observer = new MutationObserver(function(mutations) { + module.debug('DOM tree modified, updating selector cache'); + module.refresh(); + }); + observer.observe(element, { + childList : true, + subtree : true + }); + module.debug('Setting up mutation observer', observer); + } + }, + + bind: { + events: function() { + module.debug('Binding delegated events'); + $module + .on(settings.on + eventNamespace, selector.trigger, module.event.click) + ; + } + }, + + event: { + click: function() { + module.toggle.call(this); + } + }, + + toggle: function(query) { + var + $activeTitle = (query !== undefined) + ? (typeof query === 'number') + ? $title.eq(query) + : $(query).closest(selector.title) + : $(this).closest(selector.title), + $activeContent = $activeTitle.next($content), + isAnimating = $activeContent.hasClass(className.animating), + isActive = $activeContent.hasClass(className.active), + isOpen = (isActive && !isAnimating), + isOpening = (!isActive && isAnimating) + ; + module.debug('Toggling visibility of content', $activeTitle); + if(isOpen || isOpening) { + if(settings.collapsible) { + module.close.call($activeTitle); + } + else { + module.debug('Cannot close accordion content collapsing is disabled'); + } + } + else { + module.open.call($activeTitle); + } + }, + + open: function(query) { + var + $activeTitle = (query !== undefined) + ? (typeof query === 'number') + ? $title.eq(query) + : $(query).closest(selector.title) + : $(this).closest(selector.title), + $activeContent = $activeTitle.next($content), + isAnimating = $activeContent.hasClass(className.animating), + isActive = $activeContent.hasClass(className.active), + isOpen = (isActive || isAnimating) + ; + if(isOpen) { + module.debug('Accordion already open, skipping', $activeContent); + return; + } + module.debug('Opening accordion content', $activeTitle); + settings.onOpening.call($activeContent); + settings.onChanging.call($activeContent); + if(settings.exclusive) { + module.closeOthers.call($activeTitle); + } + $activeTitle + .addClass(className.active) + ; + $activeContent + .stop(true, true) + .addClass(className.animating) + ; + if(settings.animateChildren) { + if($.fn.transition !== undefined && $module.transition('is supported')) { + $activeContent + .children() + .transition({ + animation : 'fade in', + queue : false, + useFailSafe : true, + debug : settings.debug, + verbose : settings.verbose, + duration : settings.duration, + skipInlineHidden : true, + onComplete: function() { + $activeContent.children().removeClass(className.transition); + } + }) + ; + } + else { + $activeContent + .children() + .stop(true, true) + .animate({ + opacity: 1 + }, settings.duration, module.resetOpacity) + ; + } + } + $activeContent + .slideDown(settings.duration, settings.easing, function() { + $activeContent + .removeClass(className.animating) + .addClass(className.active) + ; + module.reset.display.call(this); + settings.onOpen.call(this); + settings.onChange.call(this); + }) + ; + }, + + close: function(query) { + var + $activeTitle = (query !== undefined) + ? (typeof query === 'number') + ? $title.eq(query) + : $(query).closest(selector.title) + : $(this).closest(selector.title), + $activeContent = $activeTitle.next($content), + isAnimating = $activeContent.hasClass(className.animating), + isActive = $activeContent.hasClass(className.active), + isOpening = (!isActive && isAnimating), + isClosing = (isActive && isAnimating) + ; + if((isActive || isOpening) && !isClosing) { + module.debug('Closing accordion content', $activeContent); + settings.onClosing.call($activeContent); + settings.onChanging.call($activeContent); + $activeTitle + .removeClass(className.active) + ; + $activeContent + .stop(true, true) + .addClass(className.animating) + ; + if(settings.animateChildren) { + if($.fn.transition !== undefined && $module.transition('is supported')) { + $activeContent + .children() + .transition({ + animation : 'fade out', + queue : false, + useFailSafe : true, + debug : settings.debug, + verbose : settings.verbose, + duration : settings.duration, + skipInlineHidden : true + }) + ; + } + else { + $activeContent + .children() + .stop(true, true) + .animate({ + opacity: 0 + }, settings.duration, module.resetOpacity) + ; + } + } + $activeContent + .slideUp(settings.duration, settings.easing, function() { + $activeContent + .removeClass(className.animating) + .removeClass(className.active) + ; + module.reset.display.call(this); + settings.onClose.call(this); + settings.onChange.call(this); + }) + ; + } + }, + + closeOthers: function(index) { + var + $activeTitle = (index !== undefined) + ? $title.eq(index) + : $(this).closest(selector.title), + $parentTitles = $activeTitle.parents(selector.content).prev(selector.title), + $activeAccordion = $activeTitle.closest(selector.accordion), + activeSelector = selector.title + '.' + className.active + ':visible', + activeContent = selector.content + '.' + className.active + ':visible', + $openTitles, + $nestedTitles, + $openContents + ; + if(settings.closeNested) { + $openTitles = $activeAccordion.find(activeSelector).not($parentTitles); + $openContents = $openTitles.next($content); + } + else { + $openTitles = $activeAccordion.find(activeSelector).not($parentTitles); + $nestedTitles = $activeAccordion.find(activeContent).find(activeSelector).not($parentTitles); + $openTitles = $openTitles.not($nestedTitles); + $openContents = $openTitles.next($content); + } + if( ($openTitles.length > 0) ) { + module.debug('Exclusive enabled, closing other content', $openTitles); + $openTitles + .removeClass(className.active) + ; + $openContents + .removeClass(className.animating) + .stop(true, true) + ; + if(settings.animateChildren) { + if($.fn.transition !== undefined && $module.transition('is supported')) { + $openContents + .children() + .transition({ + animation : 'fade out', + useFailSafe : true, + debug : settings.debug, + verbose : settings.verbose, + duration : settings.duration, + skipInlineHidden : true + }) + ; + } + else { + $openContents + .children() + .stop(true, true) + .animate({ + opacity: 0 + }, settings.duration, module.resetOpacity) + ; + } + } + $openContents + .slideUp(settings.duration , settings.easing, function() { + $(this).removeClass(className.active); + module.reset.display.call(this); + }) + ; + } + }, + + reset: { + + display: function() { + module.verbose('Removing inline display from element', this); + $(this).css('display', ''); + if( $(this).attr('style') === '') { + $(this) + .attr('style', '') + .removeAttr('style') + ; + } + }, + + opacity: function() { + module.verbose('Removing inline opacity from element', this); + $(this).css('opacity', ''); + if( $(this).attr('style') === '') { + $(this) + .attr('style', '') + .removeAttr('style') + ; + } + }, + + }, + + setting: function(name, value) { + module.debug('Changing setting', name, value); + if( $.isPlainObject(name) ) { + $.extend(true, settings, name); + } + else if(value !== undefined) { + if($.isPlainObject(settings[name])) { + $.extend(true, settings[name], value); + } + else { + settings[name] = value; + } + } + else { + return settings[name]; + } + }, + internal: function(name, value) { + module.debug('Changing internal', name, value); + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, module, name); + } + else { + module[name] = value; + } + } + else { + return module[name]; + } + }, + debug: function() { + if(!settings.silent && settings.debug) { + if(settings.performance) { + module.performance.log(arguments); + } + else { + module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); + module.debug.apply(console, arguments); + } + } + }, + verbose: function() { + if(!settings.silent && settings.verbose && settings.debug) { + if(settings.performance) { + module.performance.log(arguments); + } + else { + module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); + module.verbose.apply(console, arguments); + } + } + }, + error: function() { + if(!settings.silent) { + module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); + module.error.apply(console, arguments); + } + }, + performance: { + log: function(message) { + var + currentTime, + executionTime, + previousTime + ; + if(settings.performance) { + currentTime = new Date().getTime(); + previousTime = time || currentTime; + executionTime = currentTime - previousTime; + time = currentTime; + performance.push({ + 'Name' : message[0], + 'Arguments' : [].slice.call(message, 1) || '', + 'Element' : element, + 'Execution Time' : executionTime + }); + } + clearTimeout(module.performance.timer); + module.performance.timer = setTimeout(module.performance.display, 500); + }, + display: function() { + var + title = settings.name + ':', + totalTime = 0 + ; + time = false; + clearTimeout(module.performance.timer); + $.each(performance, function(index, data) { + totalTime += data['Execution Time']; + }); + title += ' ' + totalTime + 'ms'; + if(moduleSelector) { + title += ' \'' + moduleSelector + '\''; + } + if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { + console.groupCollapsed(title); + if(console.table) { + console.table(performance); + } + else { + $.each(performance, function(index, data) { + console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); + }); + } + console.groupEnd(); + } + performance = []; + } + }, + invoke: function(query, passedArguments, context) { + var + object = instance, + maxDepth, + found, + response + ; + passedArguments = passedArguments || queryArguments; + context = element || context; + if(typeof query == 'string' && object !== undefined) { + query = query.split(/[\. ]/); + maxDepth = query.length - 1; + $.each(query, function(depth, value) { + var camelCaseValue = (depth != maxDepth) + ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) + : query + ; + if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { + object = object[camelCaseValue]; + } + else if( object[camelCaseValue] !== undefined ) { + found = object[camelCaseValue]; + return false; + } + else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { + object = object[value]; + } + else if( object[value] !== undefined ) { + found = object[value]; + return false; + } + else { + module.error(error.method, query); + return false; + } + }); + } + if ( $.isFunction( found ) ) { + response = found.apply(context, passedArguments); + } + else if(found !== undefined) { + response = found; + } + if(Array.isArray(returnedValue)) { + returnedValue.push(response); + } + else if(returnedValue !== undefined) { + returnedValue = [returnedValue, response]; + } + else if(response !== undefined) { + returnedValue = response; + } + return found; + } + }; + if(methodInvoked) { + if(instance === undefined) { + module.initialize(); + } + module.invoke(query); + } + else { + if(instance !== undefined) { + instance.invoke('destroy'); + } + module.initialize(); + } + }) + ; + return (returnedValue !== undefined) + ? returnedValue + : this + ; +}; + +$.fn.accordion.settings = { + + name : 'Accordion', + namespace : 'accordion', + + silent : false, + debug : false, + verbose : false, + performance : true, + + on : 'click', // event on title that opens accordion + + observeChanges : true, // whether accordion should automatically refresh on DOM insertion + + exclusive : true, // whether a single accordion content panel should be open at once + collapsible : true, // whether accordion content can be closed + closeNested : false, // whether nested content should be closed when a panel is closed + animateChildren : true, // whether children opacity should be animated + + duration : 350, // duration of animation + easing : 'easeOutQuad', // easing equation for animation + + onOpening : function(){}, // callback before open animation + onClosing : function(){}, // callback before closing animation + onChanging : function(){}, // callback before closing or opening animation + + onOpen : function(){}, // callback after open animation + onClose : function(){}, // callback after closing animation + onChange : function(){}, // callback after closing or opening animation + + error: { + method : 'The method you called is not defined' + }, + + className : { + active : 'active', + animating : 'animating', + transition: 'transition' + }, + + selector : { + accordion : '.accordion', + title : '.title', + trigger : '.title', + content : '.content' + } + +}; + +// Adds easing +$.extend( $.easing, { + easeOutQuad: function (x, t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + } +}); + +})( jQuery, window, document ); + diff --git a/semantic/src/definitions/modules/accordion.less b/semantic/src/definitions/modules/accordion.less new file mode 100644 index 0000000..7fe052f --- /dev/null +++ b/semantic/src/definitions/modules/accordion.less @@ -0,0 +1,219 @@ +/*! + * # Fomantic-UI - Accordion + * http://github.com/fomantic/Fomantic-UI/ + * + * + * Released under the MIT license + * http://opensource.org/licenses/MIT + * + */ + +/******************************* + Theme +*******************************/ + +@type : 'module'; +@element : 'accordion'; + +@import (multiple) '../../theme.config'; + +/******************************* + Accordion +*******************************/ + +.ui.accordion, +.ui.accordion .accordion { + max-width: 100%; +} +.ui.accordion .accordion { + margin: @childAccordionMargin; + padding: @childAccordionPadding; +} + +/* Title */ +.ui.accordion .title, +.ui.accordion .accordion .title { + cursor: pointer; +} + +/* Default Styling */ +.ui.accordion .title:not(.ui) { + padding: @titlePadding; + font-family: @titleFont; + font-size: @titleFontSize; + color: @titleColor; +} + +/* Default Styling */ +.ui.accordion:not(.styled) .title ~ .content:not(.ui), +.ui.accordion:not(.styled) .accordion .title ~ .content:not(.ui) { + margin: @contentMargin; + padding: @contentPadding; +} +.ui.accordion:not(.styled) .title ~ .content:not(.ui):last-child { + padding-bottom: 0; +} + +/* Arrow */ +.ui.accordion .title .dropdown.icon, +.ui.accordion .accordion .title .dropdown.icon { + display: @iconDisplay; + float: @iconFloat; + opacity: @iconOpacity; + width: @iconWidth; + height: @iconHeight; + margin: @iconMargin; + padding: @iconPadding; + font-size: @iconFontSize; + transition: @iconTransition; + vertical-align: @iconVerticalAlign; + transform: @iconTransform; +} + +/*-------------- + Coupling +---------------*/ + +/* Menu */ +.ui.accordion.menu .item .title { + display: block; + padding: @menuTitlePadding; +} +.ui.accordion.menu .item .title > .dropdown.icon { + float: @menuIconFloat; + margin: @menuIconMargin; + transform: @menuIconTransform; +} + +/* Header */ +.ui.accordion .ui.header .dropdown.icon { + font-size: @iconFontSize; + margin: @iconMargin; +} + +/******************************* + States +*******************************/ + +.ui.accordion .active.title .dropdown.icon, +.ui.accordion .accordion .active.title .dropdown.icon { + transform: @activeIconTransform; +} + +.ui.accordion.menu .item .active.title > .dropdown.icon { + transform: @activeIconTransform; +} + +/******************************* + Types +*******************************/ + +& when (@variationAccordionStyled) { + /*-------------- + Styled + ---------------*/ + + .ui.styled.accordion { + width: @styledWidth; + } + + .ui.styled.accordion, + .ui.styled.accordion .accordion { + border-radius: @styledBorderRadius; + background: @styledBackground; + box-shadow: @styledBoxShadow; + } + .ui.styled.accordion .title, + .ui.styled.accordion .accordion .title { + margin: @styledTitleMargin; + padding: @styledTitlePadding; + color: @styledTitleColor; + font-weight: @styledTitleFontWeight; + border-top: @styledTitleBorder; + transition: @styledTitleTransition; + } + .ui.styled.accordion > .title:first-child, + .ui.styled.accordion .accordion .title:first-child { + border-top: none; + } + + + /* Content */ + .ui.styled.accordion .content, + .ui.styled.accordion .accordion .content { + margin: @styledContentMargin; + padding: @styledContentPadding; + } + .ui.styled.accordion .accordion .content { + margin: @styledChildContentMargin; + padding: @styledChildContentPadding; + } + + + /* Hover */ + .ui.styled.accordion .title:hover, + .ui.styled.accordion .active.title, + .ui.styled.accordion .accordion .title:hover, + .ui.styled.accordion .accordion .active.title { + background: @styledTitleHoverBackground; + color: @styledTitleHoverColor; + } + .ui.styled.accordion .accordion .title:hover, + .ui.styled.accordion .accordion .active.title { + background: @styledHoverChildTitleBackground; + color: @styledHoverChildTitleColor; + } + + + /* Active */ + .ui.styled.accordion .active.title { + background: @styledActiveTitleBackground; + color: @styledActiveTitleColor; + } + .ui.styled.accordion .accordion .active.title { + background: @styledActiveChildTitleBackground; + color: @styledActiveChildTitleColor; + } +} + + +/******************************* + States +*******************************/ + +/*-------------- + Not Active +---------------*/ + +.ui.accordion .title ~ .content:not(.active), +.ui.accordion .accordion .title ~ .content:not(.active) { + display: none; +} + +/******************************* + Variations +*******************************/ + +& when (@variationAccordionFluid) { + /*-------------- + Fluid + ---------------*/ + + .ui.fluid.accordion, + .ui.fluid.accordion .accordion { + width: 100%; + } +} + +& when (@variationAccordionInverted) { + /*-------------- + Inverted + ---------------*/ + + .ui.inverted.accordion .title:not(.ui) { + color: @invertedTitleColor; + } +} + +.loadUIOverrides(); + diff --git a/semantic/src/definitions/modules/calendar.js b/semantic/src/definitions/modules/calendar.js new file mode 100644 index 0000000..1757f32 --- /dev/null +++ b/semantic/src/definitions/modules/calendar.js @@ -0,0 +1,1774 @@ +/*! + * # Fomantic-UI - Calendar + * http://github.com/fomantic/Fomantic-UI/ + * + * + * Released under the MIT license + * http://opensource.org/licenses/MIT + * + */ + +;(function ($, window, document, undefined) { + +'use strict'; + +$.isFunction = $.isFunction || function(obj) { + return typeof obj === "function" && typeof obj.nodeType !== "number"; +}; + +window = (typeof window != 'undefined' && window.Math == Math) + ? window + : (typeof self != 'undefined' && self.Math == Math) + ? self + : Function('return this')() +; + +$.fn.calendar = function(parameters) { + var + $allModules = $(this), + + moduleSelector = $allModules.selector || '', + + time = new Date().getTime(), + performance = [], + + query = arguments[0], + methodInvoked = (typeof query == 'string'), + queryArguments = [].slice.call(arguments, 1), + returnedValue, + timeGapTable = { + '5': {'row': 4, 'column': 3 }, + '10': {'row': 3, 'column': 2 }, + '15': {'row': 2, 'column': 2 }, + '20': {'row': 3, 'column': 1 }, + '30': {'row': 2, 'column': 1 } + }, + numberText = ['','one','two','three','four','five','six','seven','eight'] + ; + + $allModules + .each(function () { + var + settings = ( $.isPlainObject(parameters) ) + ? $.extend(true, {}, $.fn.calendar.settings, parameters) + : $.extend({}, $.fn.calendar.settings), + + className = settings.className, + namespace = settings.namespace, + selector = settings.selector, + formatter = settings.formatter, + parser = settings.parser, + metadata = settings.metadata, + timeGap = timeGapTable[settings.minTimeGap], + error = settings.error, + + eventNamespace = '.' + namespace, + moduleNamespace = 'module-' + namespace, + + $module = $(this), + $input = $module.find(selector.input), + $container = $module.find(selector.popup), + $activator = $module.find(selector.activator), + + element = this, + instance = $module.data(moduleNamespace), + + isTouch, + isTouchDown = false, + isInverted = $module.hasClass(className.inverted), + focusDateUsedForRange = false, + selectionComplete = false, + classObserver, + module + ; + + module = { + + initialize: function () { + module.debug('Initializing calendar for', element, $module); + + isTouch = module.get.isTouch(); + module.setup.config(); + module.setup.popup(); + module.setup.inline(); + module.setup.input(); + module.setup.date(); + module.create.calendar(); + + module.bind.events(); + module.observeChanges(); + module.instantiate(); + }, + + instantiate: function () { + module.verbose('Storing instance of calendar'); + instance = module; + $module.data(moduleNamespace, instance); + }, + + destroy: function () { + module.verbose('Destroying previous calendar for', element); + $module.removeData(moduleNamespace); + module.unbind.events(); + module.disconnect.classObserver(); + }, + + setup: { + config: function () { + if (module.get.minDate() !== null) { + module.set.minDate($module.data(metadata.minDate)); + } + if (module.get.maxDate() !== null) { + module.set.maxDate($module.data(metadata.maxDate)); + } + module.setting('type', module.get.type()); + module.setting('on', settings.on || ($input.length ? 'focus' : 'click')); + }, + popup: function () { + if (settings.inline) { + return; + } + if (!$activator.length) { + $activator = $module.children().first(); + if (!$activator.length) { + return; + } + } + if ($.fn.popup === undefined) { + module.error(error.popup); + return; + } + if (!$container.length) { + //prepend the popup element to the activator's parent so that it has less chance of messing with + //the styling (eg input action button needs to be the last child to have correct border radius) + var $activatorParent = $activator.parent(), + domPositionFunction = $activatorParent.closest(selector.append).length !== 0 ? 'appendTo' : 'prependTo'; + $container = $('
').addClass(className.popup)[domPositionFunction]($activatorParent); + } + $container.addClass(className.calendar); + if(isInverted){ + $container.addClass(className.inverted); + } + var onVisible = function () { + module.refreshTooltips(); + return settings.onVisible.apply($container, arguments); + }; + var onHidden = settings.onHidden; + if (!$input.length) { + //no input, $container has to handle focus/blur + $container.attr('tabindex', '0'); + onVisible = function () { + module.refreshTooltips(); + module.focus(); + return settings.onVisible.apply($container, arguments); + }; + onHidden = function () { + module.blur(); + return settings.onHidden.apply($container, arguments); + }; + } + var onShow = function () { + //reset the focus date onShow + module.set.focusDate(module.get.date()); + module.set.mode(module.get.validatedMode(settings.startMode)); + return settings.onShow.apply($container, arguments); + }; + var on = module.setting('on'); + var options = $.extend({}, settings.popupOptions, { + popup: $container, + on: on, + hoverable: on === 'hover', + closable: on === 'click', + onShow: onShow, + onVisible: onVisible, + onHide: settings.onHide, + onHidden: onHidden + }); + module.popup(options); + }, + inline: function () { + if ($activator.length && !settings.inline) { + return; + } + settings.inline = true; + $container = $('
').addClass(className.calendar).appendTo($module); + if (!$input.length) { + $container.attr('tabindex', '0'); + } + }, + input: function () { + if (settings.touchReadonly && $input.length && isTouch) { + $input.prop('readonly', true); + } + module.check.disabled(); + }, + date: function () { + var date; + if (settings.initialDate) { + date = parser.date(settings.initialDate, settings); + } else if ($module.data(metadata.date) !== undefined) { + date = parser.date($module.data(metadata.date), settings); + } else if ($input.length) { + date = parser.date($input.val(), settings); + } + module.set.date(date, settings.formatInput, false); + module.set.mode(module.get.mode(), false); + } + }, + + trigger: { + change: function() { + var + inputElement = $input[0] + ; + if(inputElement) { + var events = document.createEvent('HTMLEvents'); + module.verbose('Triggering native change event'); + events.initEvent('change', true, false); + inputElement.dispatchEvent(events); + } + } + }, + + create: { + calendar: function () { + var i, r, c, p, row, cell, pageGrid; + + var + mode = module.get.mode(), + today = new Date(), + date = module.get.date(), + focusDate = module.get.focusDate(), + display = module.helper.dateInRange(focusDate || date || settings.initialDate || today) + ; + + if (!focusDate) { + focusDate = display; + module.set.focusDate(focusDate, false, false); + } + + var + isYear = mode === 'year', + isMonth = mode === 'month', + isDay = mode === 'day', + isHour = mode === 'hour', + isMinute = mode === 'minute', + isTimeOnly = settings.type === 'time' + ; + + var multiMonth = Math.max(settings.multiMonth, 1); + var monthOffset = !isDay ? 0 : module.get.monthOffset(); + + var + minute = display.getMinutes(), + hour = display.getHours(), + day = display.getDate(), + startMonth = display.getMonth() + monthOffset, + year = display.getFullYear() + ; + + var columns = isDay ? settings.showWeekNumbers ? 8 : 7 : isHour ? 4 : timeGap['column']; + var rows = isDay || isHour ? 6 : timeGap['row']; + var pages = isDay ? multiMonth : 1; + + var container = $container; + var tooltipPosition = container.hasClass("left") ? "right center" : "left center"; + container.empty(); + if (pages > 1) { + pageGrid = $('
').addClass(className.grid).appendTo(container); + } + + for (p = 0; p < pages; p++) { + if (pages > 1) { + var pageColumn = $('
').addClass(className.column).appendTo(pageGrid); + container = pageColumn; + } + + var month = startMonth + p; + var firstMonthDayColumn = (new Date(year, month, 1).getDay() - settings.firstDayOfWeek % 7 + 7) % 7; + if (!settings.constantHeight && isDay) { + var requiredCells = new Date(year, month + 1, 0).getDate() + firstMonthDayColumn; + rows = Math.ceil(requiredCells / 7); + } + + var + yearChange = isYear ? 10 : isMonth ? 1 : 0, + monthChange = isDay ? 1 : 0, + dayChange = isHour || isMinute ? 1 : 0, + prevNextDay = isHour || isMinute ? day : 1, + prevDate = new Date(year - yearChange, month - monthChange, prevNextDay - dayChange, hour), + nextDate = new Date(year + yearChange, month + monthChange, prevNextDay + dayChange, hour), + prevLast = isYear ? new Date(Math.ceil(year / 10) * 10 - 9, 0, 0) : + isMonth ? new Date(year, 0, 0) : isDay ? new Date(year, month, 0) : new Date(year, month, day, -1), + nextFirst = isYear ? new Date(Math.ceil(year / 10) * 10 + 1, 0, 1) : + isMonth ? new Date(year + 1, 0, 1) : isDay ? new Date(year, month + 1, 1) : new Date(year, month, day + 1) + ; + + var tempMode = mode; + if (isDay && settings.showWeekNumbers){ + tempMode += ' andweek'; + } + var table = $('').addClass(className.table).addClass(tempMode).addClass(numberText[columns] + ' column').appendTo(container); + if(isInverted){ + table.addClass(className.inverted); + } + var textColumns = columns; + //no header for time-only mode + if (!isTimeOnly) { + var thead = $('').appendTo(table); + + row = $('').appendTo(thead); + cell = $('').appendTo(thead); + if(settings.showWeekNumbers) { + cell = $('').appendTo(table); + i = isYear ? Math.ceil(year / 10) * 10 - 9 : isDay ? 1 - firstMonthDayColumn : 0; + for (r = 0; r < rows; r++) { + row = $('').appendTo(tbody); + if(isDay && settings.showWeekNumbers){ + cell = $('').appendTo(tbody); + var todayButton = $('
').attr('colspan', '' + columns).appendTo(row); + + var headerDate = isYear || isMonth ? new Date(year, 0, 1) : + isDay ? new Date(year, month, 1) : new Date(year, month, day, hour, minute); + var headerText = $('').addClass(className.link).appendTo(cell); + headerText.text(formatter.header(headerDate, mode, settings)); + var newMode = isMonth ? (settings.disableYear ? 'day' : 'year') : + isDay ? (settings.disableMonth ? 'year' : 'month') : 'day'; + headerText.data(metadata.mode, newMode); + + if (p === 0) { + var prev = $('').addClass(className.prev).appendTo(cell); + prev.data(metadata.focusDate, prevDate); + prev.toggleClass(className.disabledCell, !module.helper.isDateInRange(prevLast, mode)); + $('').addClass(className.prevIcon).appendTo(prev); + } + + if (p === pages - 1) { + var next = $('').addClass(className.next).appendTo(cell); + next.data(metadata.focusDate, nextDate); + next.toggleClass(className.disabledCell, !module.helper.isDateInRange(nextFirst, mode)); + $('').addClass(className.nextIcon).appendTo(next); + } + if (isDay) { + row = $('
').appendTo(row); + cell.text(settings.text.weekNo); + cell.addClass(className.weekCell); + textColumns--; + } + for (i = 0; i < textColumns; i++) { + cell = $('').appendTo(row); + cell.text(formatter.dayColumnHeader((i + settings.firstDayOfWeek) % 7, settings)); + } + } + } + + var tbody = $('
').appendTo(row); + cell.text(module.get.weekOfYear(year,month,i+1-settings.firstDayOfWeek)); + cell.addClass(className.weekCell); + } + for (c = 0; c < textColumns; c++, i++) { + var cellDate = isYear ? new Date(i, month, 1, hour, minute) : + isMonth ? new Date(year, i, 1, hour, minute) : isDay ? new Date(year, month, i, hour, minute) : + isHour ? new Date(year, month, day, i) : new Date(year, month, day, hour, i * settings.minTimeGap); + var cellText = isYear ? i : + isMonth ? settings.text.monthsShort[i] : isDay ? cellDate.getDate() : + formatter.time(cellDate, settings, true); + cell = $('').addClass(className.cell).appendTo(row); + cell.text(cellText); + cell.data(metadata.date, cellDate); + var adjacent = isDay && cellDate.getMonth() !== ((month + 12) % 12); + var disabled = (!settings.selectAdjacentDays && adjacent) || !module.helper.isDateInRange(cellDate, mode) || settings.isDisabled(cellDate, mode) || module.helper.isDisabled(cellDate, mode) || !module.helper.isEnabled(cellDate, mode); + if (disabled) { + var disabledDate = module.helper.findDayAsObject(cellDate, mode, settings.disabledDates); + if (disabledDate !== null && disabledDate[metadata.message]) { + cell.attr("data-tooltip", disabledDate[metadata.message]); + cell.attr("data-position", disabledDate[metadata.position] || tooltipPosition); + if(disabledDate[metadata.inverted] || (isInverted && disabledDate[metadata.inverted] === undefined)) { + cell.attr("data-inverted", ''); + } + if(disabledDate[metadata.variation]) { + cell.attr("data-variation", disabledDate[metadata.variation]); + } + } + } else { + var eventDate = module.helper.findDayAsObject(cellDate, mode, settings.eventDates); + if (eventDate !== null) { + cell.addClass(eventDate[metadata.class] || settings.eventClass); + if (eventDate[metadata.message]) { + cell.attr("data-tooltip", eventDate[metadata.message]); + cell.attr("data-position", eventDate[metadata.position] || tooltipPosition); + if(eventDate[metadata.inverted] || (isInverted && eventDate[metadata.inverted] === undefined)) { + cell.attr("data-inverted", ''); + } + if(eventDate[metadata.variation]) { + cell.attr("data-variation", eventDate[metadata.variation]); + } + } + } + } + var active = module.helper.dateEqual(cellDate, date, mode); + var isToday = module.helper.dateEqual(cellDate, today, mode); + cell.toggleClass(className.adjacentCell, adjacent); + cell.toggleClass(className.disabledCell, disabled); + cell.toggleClass(className.activeCell, active && !adjacent); + if (!isHour && !isMinute) { + cell.toggleClass(className.todayCell, !adjacent && isToday); + } + + // Allow for external modifications of each cell + var cellOptions = { + mode: mode, + adjacent: adjacent, + disabled: disabled, + active: active, + today: isToday + }; + formatter.cell(cell, cellDate, cellOptions); + + if (module.helper.dateEqual(cellDate, focusDate, mode)) { + //ensure that the focus date is exactly equal to the cell date + //so that, if selected, the correct value is set + module.set.focusDate(cellDate, false, false); + } + } + } + + if (settings.today) { + var todayRow = $('
').attr('colspan', '' + columns).addClass(className.today).appendTo(todayRow); + todayButton.text(formatter.today(settings)); + todayButton.data(metadata.date, today); + } + + module.update.focus(false, table); + + if(settings.inline){ + module.refreshTooltips(); + } + } + } + }, + + update: { + focus: function (updateRange, container) { + container = container || $container; + var mode = module.get.mode(); + var date = module.get.date(); + var focusDate = module.get.focusDate(); + var startDate = module.get.startDate(); + var endDate = module.get.endDate(); + var rangeDate = (updateRange ? focusDate : null) || date || (!isTouch ? focusDate : null); + + container.find('td').each(function () { + var cell = $(this); + var cellDate = cell.data(metadata.date); + if (!cellDate) { + return; + } + var disabled = cell.hasClass(className.disabledCell); + var active = cell.hasClass(className.activeCell); + var adjacent = cell.hasClass(className.adjacentCell); + var focused = module.helper.dateEqual(cellDate, focusDate, mode); + var inRange = !rangeDate ? false : + ((!!startDate && module.helper.isDateInRange(cellDate, mode, startDate, rangeDate)) || + (!!endDate && module.helper.isDateInRange(cellDate, mode, rangeDate, endDate))); + cell.toggleClass(className.focusCell, focused && (!isTouch || isTouchDown) && (!adjacent || (settings.selectAdjacentDays && adjacent)) && !disabled); + + if (module.helper.isTodayButton(cell)) { + return; + } + cell.toggleClass(className.rangeCell, inRange && !active && !disabled); + }); + } + }, + + refresh: function () { + module.create.calendar(); + }, + + refreshTooltips: function() { + var winWidth = $(window).width(); + $container.find('td[data-position]').each(function () { + var cell = $(this); + var tooltipWidth = window.getComputedStyle(cell[0], ':after').width.replace(/[^0-9\.]/g,''); + var tooltipPosition = cell.attr('data-position'); + // use a fallback width of 250 (calendar width) for IE/Edge (which return "auto") + var calcPosition = (winWidth - cell.width() - (parseInt(tooltipWidth,10) || 250)) > cell.offset().left ? 'right' : 'left'; + if(tooltipPosition.indexOf(calcPosition) === -1) { + cell.attr('data-position',tooltipPosition.replace(/(left|right)/,calcPosition)); + } + }); + }, + + bind: { + events: function () { + module.debug('Binding events'); + $container.on('mousedown' + eventNamespace, module.event.mousedown); + $container.on('touchstart' + eventNamespace, module.event.mousedown); + $container.on('mouseup' + eventNamespace, module.event.mouseup); + $container.on('touchend' + eventNamespace, module.event.mouseup); + $container.on('mouseover' + eventNamespace, module.event.mouseover); + if ($input.length) { + $input.on('input' + eventNamespace, module.event.inputChange); + $input.on('focus' + eventNamespace, module.event.inputFocus); + $input.on('blur' + eventNamespace, module.event.inputBlur); + $input.on('keydown' + eventNamespace, module.event.keydown); + } else { + $container.on('keydown' + eventNamespace, module.event.keydown); + } + } + }, + + unbind: { + events: function () { + module.debug('Unbinding events'); + $container.off(eventNamespace); + if ($input.length) { + $input.off(eventNamespace); + } + } + }, + + event: { + mouseover: function (event) { + var target = $(event.target); + var date = target.data(metadata.date); + var mousedown = event.buttons === 1; + if (date) { + module.set.focusDate(date, false, true, mousedown); + } + }, + mousedown: function (event) { + if ($input.length) { + //prevent the mousedown on the calendar causing the input to lose focus + event.preventDefault(); + } + isTouchDown = event.type.indexOf('touch') >= 0; + var target = $(event.target); + var date = target.data(metadata.date); + if (date) { + module.set.focusDate(date, false, true, true); + } + }, + mouseup: function (event) { + //ensure input has focus so that it receives keydown events for calendar navigation + module.focus(); + event.preventDefault(); + event.stopPropagation(); + isTouchDown = false; + var target = $(event.target); + if (target.hasClass("disabled")) { + return; + } + var parent = target.parent(); + if (parent.data(metadata.date) || parent.data(metadata.focusDate) || parent.data(metadata.mode)) { + //clicked on a child element, switch to parent (used when clicking directly on prev/next icon element) + target = parent; + } + var date = target.data(metadata.date); + var focusDate = target.data(metadata.focusDate); + var mode = target.data(metadata.mode); + if (date && settings.onSelect.call(element, date, module.get.mode()) !== false) { + var forceSet = target.hasClass(className.today); + module.selectDate(date, forceSet); + } + else if (focusDate) { + module.set.focusDate(focusDate); + } + else if (mode) { + module.set.mode(mode); + } + }, + keydown: function (event) { + var keyCode = event.which; + if (keyCode === 27 || keyCode === 9) { + //esc || tab + module.popup('hide'); + } + + if (module.popup('is visible')) { + if (keyCode === 37 || keyCode === 38 || keyCode === 39 || keyCode === 40) { + //arrow keys + var mode = module.get.mode(); + var bigIncrement = mode === 'day' ? 7 : mode === 'hour' ? 4 : mode === 'minute' ? timeGap['column'] : 3; + var increment = keyCode === 37 ? -1 : keyCode === 38 ? -bigIncrement : keyCode == 39 ? 1 : bigIncrement; + increment *= mode === 'minute' ? settings.minTimeGap : 1; + var focusDate = module.get.focusDate() || module.get.date() || new Date(); + var year = focusDate.getFullYear() + (mode === 'year' ? increment : 0); + var month = focusDate.getMonth() + (mode === 'month' ? increment : 0); + var day = focusDate.getDate() + (mode === 'day' ? increment : 0); + var hour = focusDate.getHours() + (mode === 'hour' ? increment : 0); + var minute = focusDate.getMinutes() + (mode === 'minute' ? increment : 0); + var newFocusDate = new Date(year, month, day, hour, minute); + if (settings.type === 'time') { + newFocusDate = module.helper.mergeDateTime(focusDate, newFocusDate); + } + if (module.helper.isDateInRange(newFocusDate, mode)) { + module.set.focusDate(newFocusDate); + } + } else if (keyCode === 13) { + //enter + var mode = module.get.mode(); + var date = module.get.focusDate(); + if (date && !settings.isDisabled(date, mode) && !module.helper.isDisabled(date, mode) && module.helper.isEnabled(date, mode)) { + module.selectDate(date); + } + //disable form submission: + event.preventDefault(); + event.stopPropagation(); + } + } + + if (keyCode === 38 || keyCode === 40) { + //arrow-up || arrow-down + event.preventDefault(); //don't scroll + module.popup('show'); + } + }, + inputChange: function () { + var val = $input.val(); + var date = parser.date(val, settings); + module.set.date(date, false); + }, + inputFocus: function () { + $container.addClass(className.active); + }, + inputBlur: function () { + $container.removeClass(className.active); + if (settings.formatInput) { + var date = module.get.date(); + var text = formatter.datetime(date, settings); + $input.val(text); + } + if(selectionComplete){ + module.trigger.change(); + selectionComplete = false; + } + }, + class: { + mutation: function(mutations) { + mutations.forEach(function(mutation) { + if(mutation.attributeName === "class") { + module.check.disabled(); + } + }); + } + } + }, + + observeChanges: function() { + if('MutationObserver' in window) { + classObserver = new MutationObserver(module.event.class.mutation); + module.debug('Setting up mutation observer', classObserver); + module.observe.class(); + } + }, + + disconnect: { + classObserver: function() { + if($input.length && classObserver) { + classObserver.disconnect(); + } + } + }, + + observe: { + class: function() { + if($input.length && classObserver) { + classObserver.observe($module[0], { + attributes : true + }); + } + } + }, + + is: { + disabled: function() { + return $module.hasClass(className.disabled); + } + }, + + check: { + disabled: function(){ + $input.attr('tabindex',module.is.disabled() ? -1 : 0); + } + }, + + get: { + weekOfYear: function(weekYear,weekMonth,weekDay) { + // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm + var ms1d = 864e5, // milliseconds in a day + ms7d = 7 * ms1d; // milliseconds in a week + + return function() { // return a closure so constants get calculated only once + var DC3 = Date.UTC(weekYear, weekMonth, weekDay + 3) / ms1d, // an Absolute Day Number + AWN = Math.floor(DC3 / 7), // an Absolute Week Number + Wyr = new Date(AWN * ms7d).getUTCFullYear(); + + return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1; + }(); + }, + date: function () { + return module.helper.sanitiseDate($module.data(metadata.date)) || null; + }, + inputDate: function() { + return $input.val(); + }, + focusDate: function () { + return $module.data(metadata.focusDate) || null; + }, + startDate: function () { + var startModule = module.get.calendarModule(settings.startCalendar); + return (startModule ? startModule.get.date() : $module.data(metadata.startDate)) || null; + }, + endDate: function () { + var endModule = module.get.calendarModule(settings.endCalendar); + return (endModule ? endModule.get.date() : $module.data(metadata.endDate)) || null; + }, + minDate: function() { + return $module.data(metadata.minDate) || null; + }, + maxDate: function() { + return $module.data(metadata.maxDate) || null; + }, + monthOffset: function () { + return $module.data(metadata.monthOffset) || 0; + }, + mode: function () { + //only returns valid modes for the current settings + var mode = $module.data(metadata.mode) || settings.startMode; + return module.get.validatedMode(mode); + }, + validatedMode: function(mode){ + var validModes = module.get.validModes(); + if ($.inArray(mode, validModes) >= 0) { + return mode; + } + return settings.type === 'time' ? 'hour' : + settings.type === 'month' ? 'month' : + settings.type === 'year' ? 'year' : 'day'; + }, + type: function() { + return $module.data(metadata.type) || settings.type; + }, + validModes: function () { + var validModes = []; + if (settings.type !== 'time') { + if (!settings.disableYear || settings.type === 'year') { + validModes.push('year'); + } + if (!(settings.disableMonth || settings.type === 'year') || settings.type === 'month') { + validModes.push('month'); + } + if (settings.type.indexOf('date') >= 0) { + validModes.push('day'); + } + } + if (settings.type.indexOf('time') >= 0) { + validModes.push('hour'); + if (!settings.disableMinute) { + validModes.push('minute'); + } + } + return validModes; + }, + isTouch: function () { + try { + document.createEvent('TouchEvent'); + return true; + } + catch (e) { + return false; + } + }, + calendarModule: function (selector) { + if (!selector) { + return null; + } + if (!(selector instanceof $)) { + selector = $(selector).first(); + } + //assume range related calendars are using the same namespace + return selector.data(moduleNamespace); + } + }, + + set: { + date: function (date, updateInput, fireChange) { + updateInput = updateInput !== false; + fireChange = fireChange !== false; + date = module.helper.sanitiseDate(date); + date = module.helper.dateInRange(date); + + var mode = module.get.mode(); + var text = formatter.datetime(date, settings); + + if (fireChange && settings.onBeforeChange.call(element, date, text, mode) === false) { + return false; + } + + module.set.focusDate(date); + + if (settings.isDisabled(date, mode)) { + return false; + } + + var endDate = module.get.endDate(); + if (!!endDate && !!date && date > endDate) { + //selected date is greater than end date in range, so clear end date + module.set.endDate(undefined); + } + module.set.dataKeyValue(metadata.date, date); + + if (updateInput && $input.length) { + $input.val(text); + } + + if (fireChange) { + settings.onChange.call(element, date, text, mode); + } + }, + startDate: function (date, refreshCalendar) { + date = module.helper.sanitiseDate(date); + var startModule = module.get.calendarModule(settings.startCalendar); + if (startModule) { + startModule.set.date(date); + } + module.set.dataKeyValue(metadata.startDate, date, refreshCalendar); + }, + endDate: function (date, refreshCalendar) { + date = module.helper.sanitiseDate(date); + var endModule = module.get.calendarModule(settings.endCalendar); + if (endModule) { + endModule.set.date(date); + } + module.set.dataKeyValue(metadata.endDate, date, refreshCalendar); + }, + focusDate: function (date, refreshCalendar, updateFocus, updateRange) { + date = module.helper.sanitiseDate(date); + date = module.helper.dateInRange(date); + var isDay = module.get.mode() === 'day'; + var oldFocusDate = module.get.focusDate(); + if (isDay && date && oldFocusDate) { + var yearDelta = date.getFullYear() - oldFocusDate.getFullYear(); + var monthDelta = yearDelta * 12 + date.getMonth() - oldFocusDate.getMonth(); + if (monthDelta) { + var monthOffset = module.get.monthOffset() - monthDelta; + module.set.monthOffset(monthOffset, false); + } + } + var changed = module.set.dataKeyValue(metadata.focusDate, date, !!date && refreshCalendar); + updateFocus = (updateFocus !== false && changed && refreshCalendar === false) || focusDateUsedForRange != updateRange; + focusDateUsedForRange = updateRange; + if (updateFocus) { + module.update.focus(updateRange); + } + }, + minDate: function (date) { + date = module.helper.sanitiseDate(date); + if (settings.maxDate !== null && settings.maxDate <= date) { + module.verbose('Unable to set minDate variable bigger that maxDate variable', date, settings.maxDate); + } else { + module.setting('minDate', date); + module.set.dataKeyValue(metadata.minDate, date); + } + }, + maxDate: function (date) { + date = module.helper.sanitiseDate(date); + if (settings.minDate !== null && settings.minDate >= date) { + module.verbose('Unable to set maxDate variable lower that minDate variable', date, settings.minDate); + } else { + module.setting('maxDate', date); + module.set.dataKeyValue(metadata.maxDate, date); + } + }, + monthOffset: function (monthOffset, refreshCalendar) { + var multiMonth = Math.max(settings.multiMonth, 1); + monthOffset = Math.max(1 - multiMonth, Math.min(0, monthOffset)); + module.set.dataKeyValue(metadata.monthOffset, monthOffset, refreshCalendar); + }, + mode: function (mode, refreshCalendar) { + module.set.dataKeyValue(metadata.mode, mode, refreshCalendar); + }, + dataKeyValue: function (key, value, refreshCalendar) { + var oldValue = $module.data(key); + var equal = oldValue === value || (oldValue <= value && oldValue >= value); //equality test for dates and string objects + if (value) { + $module.data(key, value); + } else { + $module.removeData(key); + } + refreshCalendar = refreshCalendar !== false && !equal; + if (refreshCalendar) { + module.refresh(); + } + return !equal; + } + }, + + selectDate: function (date, forceSet) { + module.verbose('New date selection', date); + var mode = module.get.mode(); + var complete = forceSet || mode === 'minute' || + (settings.disableMinute && mode === 'hour') || + (settings.type === 'date' && mode === 'day') || + (settings.type === 'month' && mode === 'month') || + (settings.type === 'year' && mode === 'year'); + if (complete) { + var canceled = module.set.date(date) === false; + if (!canceled) { + selectionComplete = true; + if(settings.closable) { + module.popup('hide'); + //if this is a range calendar, focus the container or input. This will open the popup from its event listeners. + var endModule = module.get.calendarModule(settings.endCalendar); + if (endModule) { + if (endModule.setting('on') !== 'focus') { + endModule.popup('show'); + } + endModule.focus(); + } + } + } + } else { + var newMode = mode === 'year' ? (!settings.disableMonth ? 'month' : 'day') : + mode === 'month' ? 'day' : mode === 'day' ? 'hour' : 'minute'; + module.set.mode(newMode); + if (mode === 'hour' || (mode === 'day' && module.get.date())) { + //the user has chosen enough to consider a valid date/time has been chosen + module.set.date(date, true, false); + } else { + module.set.focusDate(date); + } + } + }, + + changeDate: function (date) { + module.set.date(date); + }, + + clear: function () { + module.set.date(undefined); + }, + + popup: function () { + return $activator.popup.apply($activator, arguments); + }, + + focus: function () { + if ($input.length) { + $input.focus(); + } else { + $container.focus(); + } + }, + blur: function () { + if ($input.length) { + $input.blur(); + } else { + $container.blur(); + } + }, + + helper: { + isDisabled: function(date, mode) { + return (mode === 'day' || mode === 'month' || mode === 'year') && ((settings.disabledDaysOfWeek.indexOf(date.getDay()) !== -1) || settings.disabledDates.some(function(d){ + if(typeof d === 'string') { + d = module.helper.sanitiseDate(d); + } + if (d instanceof Date) { + return module.helper.dateEqual(date, d, mode); + } + if (d !== null && typeof d === 'object') { + if (d[metadata.year]) { + if (typeof d[metadata.year] === 'number') { + return date.getFullYear() == d[metadata.year]; + } else if (Array.isArray(d[metadata.year])) { + return d[metadata.year].indexOf(date.getFullYear()) > -1; + } + } else if (d[metadata.month]) { + if (typeof d[metadata.month] === 'number') { + return date.getMonth() == d[metadata.month]; + } else if (Array.isArray(d[metadata.month])) { + return d[metadata.month].indexOf(date.getMonth()) > -1; + } else if (d[metadata.month] instanceof Date) { + var sdate = module.helper.sanitiseDate(d[metadata.month]); + return (date.getMonth() == sdate.getMonth()) && (date.getFullYear() == sdate.getFullYear()) + } + } else if (d[metadata.date] && mode === 'day') { + if (d[metadata.date] instanceof Date) { + return module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode); + } else if (Array.isArray(d[metadata.date])) { + return d[metadata.date].some(function(idate) { + return module.helper.dateEqual(date, idate, mode); + }); + } + } + } + })); + }, + isEnabled: function(date, mode) { + if (mode === 'day') { + return settings.enabledDates.length === 0 || settings.enabledDates.some(function(d){ + if(typeof d === 'string') { + d = module.helper.sanitiseDate(d); + } + if (d instanceof Date) { + return module.helper.dateEqual(date, d, mode); + } + if (d !== null && typeof d === 'object' && d[metadata.date]) { + return module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode); + } + }); + } else { + return true; + } + }, + findDayAsObject: function(date, mode, dates) { + if (mode === 'day' || mode === 'month' || mode === 'year') { + var d; + for (var i = 0; i < dates.length; i++) { + d = dates[i]; + if(typeof d === 'string') { + d = module.helper.sanitiseDate(d); + } + if (d instanceof Date && module.helper.dateEqual(date, d, mode)) { + var dateObject = {}; + dateObject[metadata.date] = d; + return dateObject; + } + else if (d !== null && typeof d === 'object') { + if (d[metadata.year]) { + if (typeof d[metadata.year] === 'number' && date.getFullYear() == d[metadata.year]) { + return d; + } else if (Array.isArray(d[metadata.year])) { + if (d[metadata.year].indexOf(date.getFullYear()) > -1) { + return d; + } + } + } else if (d[metadata.month]) { + if (typeof d[metadata.month] === 'number' && date.getMonth() == d[metadata.month]) { + return d; + } else if (Array.isArray(d[metadata.month])) { + if (d[metadata.month].indexOf(date.getMonth()) > -1) { + return d; + } + } else if (d[metadata.month] instanceof Date) { + var sdate = module.helper.sanitiseDate(d[metadata.month]); + if ((date.getMonth() == sdate.getMonth()) && (date.getFullYear() == sdate.getFullYear())) { + return d; + } + } + } else if (d[metadata.date] && mode === 'day') { + if (d[metadata.date] instanceof Date && module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode)) { + return d; + } else if (Array.isArray(d[metadata.date])) { + if(d[metadata.date].some(function(idate) { return module.helper.dateEqual(date, idate, mode); })) { + return d; + } + } + } + } + } + } + return null; + }, + sanitiseDate: function (date) { + if (!date) { + return undefined; + } + if (!(date instanceof Date)) { + date = parser.date('' + date, settings); + } + if (!date || date === null || isNaN(date.getTime())) { + return undefined; + } + return date; + }, + dateDiff: function (date1, date2, mode) { + mode = mode || 'day'; + var isTimeOnly = settings.type === 'time'; + var isYear = mode === 'year'; + var isYearOrMonth = isYear || mode === 'month'; + var isMinute = mode === 'minute'; + var isHourOrMinute = isMinute || mode === 'hour'; + //only care about a minute accuracy of settings.minTimeGap + date1 = new Date( + isTimeOnly ? 2000 : date1.getFullYear(), + isTimeOnly ? 0 : isYear ? 0 : date1.getMonth(), + isTimeOnly ? 1 : isYearOrMonth ? 1 : date1.getDate(), + !isHourOrMinute ? 0 : date1.getHours(), + !isMinute ? 0 : settings.minTimeGap * Math.floor(date1.getMinutes() / settings.minTimeGap)); + date2 = new Date( + isTimeOnly ? 2000 : date2.getFullYear(), + isTimeOnly ? 0 : isYear ? 0 : date2.getMonth(), + isTimeOnly ? 1 : isYearOrMonth ? 1 : date2.getDate(), + !isHourOrMinute ? 0 : date2.getHours(), + !isMinute ? 0 : settings.minTimeGap * Math.floor(date2.getMinutes() / settings.minTimeGap)); + return date2.getTime() - date1.getTime(); + }, + dateEqual: function (date1, date2, mode) { + return !!date1 && !!date2 && module.helper.dateDiff(date1, date2, mode) === 0; + }, + isDateInRange: function (date, mode, minDate, maxDate) { + if (!minDate && !maxDate) { + var startDate = module.get.startDate(); + minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate; + maxDate = settings.maxDate; + } + minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap)); + return !(!date || + (minDate && module.helper.dateDiff(date, minDate, mode) > 0) || + (maxDate && module.helper.dateDiff(maxDate, date, mode) > 0)); + }, + dateInRange: function (date, minDate, maxDate) { + if (!minDate && !maxDate) { + var startDate = module.get.startDate(); + minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate; + maxDate = settings.maxDate; + } + minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap)); + var isTimeOnly = settings.type === 'time'; + return !date ? date : + (minDate && module.helper.dateDiff(date, minDate, 'minute') > 0) ? + (isTimeOnly ? module.helper.mergeDateTime(date, minDate) : minDate) : + (maxDate && module.helper.dateDiff(maxDate, date, 'minute') > 0) ? + (isTimeOnly ? module.helper.mergeDateTime(date, maxDate) : maxDate) : + date; + }, + mergeDateTime: function (date, time) { + return (!date || !time) ? time : + new Date(date.getFullYear(), date.getMonth(), date.getDate(), time.getHours(), time.getMinutes()); + }, + isTodayButton: function(element) { + return element.text() === settings.text.today; + } + }, + + setting: function (name, value) { + module.debug('Changing setting', name, value); + if ($.isPlainObject(name)) { + $.extend(true, settings, name); + } + else if (value !== undefined) { + if ($.isPlainObject(settings[name])) { + $.extend(true, settings[name], value); + } + else { + settings[name] = value; + } + } + else { + return settings[name]; + } + }, + internal: function (name, value) { + if( $.isPlainObject(name) ) { + $.extend(true, module, name); + } + else if(value !== undefined) { + module[name] = value; + } + else { + return module[name]; + } + }, + debug: function () { + if (!settings.silent && settings.debug) { + if (settings.performance) { + module.performance.log(arguments); + } + else { + module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); + module.debug.apply(console, arguments); + } + } + }, + verbose: function () { + if (!settings.silent && settings.verbose && settings.debug) { + if (settings.performance) { + module.performance.log(arguments); + } + else { + module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); + module.verbose.apply(console, arguments); + } + } + }, + error: function () { + if (!settings.silent) { + module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); + module.error.apply(console, arguments); + } + }, + performance: { + log: function (message) { + var + currentTime, + executionTime, + previousTime + ; + if (settings.performance) { + currentTime = new Date().getTime(); + previousTime = time || currentTime; + executionTime = currentTime - previousTime; + time = currentTime; + performance.push({ + 'Name': message[0], + 'Arguments': [].slice.call(message, 1) || '', + 'Element': element, + 'Execution Time': executionTime + }); + } + clearTimeout(module.performance.timer); + module.performance.timer = setTimeout(module.performance.display, 500); + }, + display: function () { + var + title = settings.name + ':', + totalTime = 0 + ; + time = false; + clearTimeout(module.performance.timer); + $.each(performance, function (index, data) { + totalTime += data['Execution Time']; + }); + title += ' ' + totalTime + 'ms'; + if (moduleSelector) { + title += ' \'' + moduleSelector + '\''; + } + if ((console.group !== undefined || console.table !== undefined) && performance.length > 0) { + console.groupCollapsed(title); + if (console.table) { + console.table(performance); + } + else { + $.each(performance, function (index, data) { + console.log(data['Name'] + ': ' + data['Execution Time'] + 'ms'); + }); + } + console.groupEnd(); + } + performance = []; + } + }, + invoke: function (query, passedArguments, context) { + var + object = instance, + maxDepth, + found, + response + ; + passedArguments = passedArguments || queryArguments; + context = element || context; + if (typeof query == 'string' && object !== undefined) { + query = query.split(/[\. ]/); + maxDepth = query.length - 1; + $.each(query, function (depth, value) { + var camelCaseValue = (depth != maxDepth) + ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) + : query + ; + if ($.isPlainObject(object[camelCaseValue]) && (depth != maxDepth)) { + object = object[camelCaseValue]; + } + else if (object[camelCaseValue] !== undefined) { + found = object[camelCaseValue]; + return false; + } + else if ($.isPlainObject(object[value]) && (depth != maxDepth)) { + object = object[value]; + } + else if (object[value] !== undefined) { + found = object[value]; + return false; + } + else { + module.error(error.method, query); + return false; + } + }); + } + if ($.isFunction(found)) { + response = found.apply(context, passedArguments); + } + else if (found !== undefined) { + response = found; + } + if (Array.isArray(returnedValue)) { + returnedValue.push(response); + } + else if (returnedValue !== undefined) { + returnedValue = [returnedValue, response]; + } + else if (response !== undefined) { + returnedValue = response; + } + return found; + } + }; + + if (methodInvoked) { + if (instance === undefined) { + module.initialize(); + } + module.invoke(query); + } + else { + if (instance !== undefined) { + instance.invoke('destroy'); + } + module.initialize(); + } + }) + ; + return (returnedValue !== undefined) + ? returnedValue + : this + ; +}; + +$.fn.calendar.settings = { + + name : 'Calendar', + namespace : 'calendar', + + silent: false, + debug: false, + verbose: false, + performance: false, + + type : 'datetime', // picker type, can be 'datetime', 'date', 'time', 'month', or 'year' + firstDayOfWeek : 0, // day for first day column (0 = Sunday) + constantHeight : true, // add rows to shorter months to keep day calendar height consistent (6 rows) + today : false, // show a 'today/now' button at the bottom of the calendar + closable : true, // close the popup after selecting a date/time + monthFirst : true, // month before day when parsing/converting date from/to text + touchReadonly : true, // set input to readonly on touch devices + inline : false, // create the calendar inline instead of inside a popup + on : null, // when to show the popup (defaults to 'focus' for input, 'click' for others) + initialDate : null, // date to display initially when no date is selected (null = now) + startMode : false, // display mode to start in, can be 'year', 'month', 'day', 'hour', 'minute' (false = 'day') + minDate : null, // minimum date/time that can be selected, dates/times before are disabled + maxDate : null, // maximum date/time that can be selected, dates/times after are disabled + ampm : true, // show am/pm in time mode + disableYear : false, // disable year selection mode + disableMonth : false, // disable month selection mode + disableMinute : false, // disable minute selection mode + formatInput : true, // format the input text upon input blur and module creation + startCalendar : null, // jquery object or selector for another calendar that represents the start date of a date range + endCalendar : null, // jquery object or selector for another calendar that represents the end date of a date range + multiMonth : 1, // show multiple months when in 'day' mode + minTimeGap : 5, + showWeekNumbers : null, // show Number of Week at the very first column of a dayView + disabledDates : [], // specific day(s) which won't be selectable and contain additional information. + disabledDaysOfWeek : [], // day(s) which won't be selectable(s) (0 = Sunday) + enabledDates : [], // specific day(s) which will be selectable, all other days will be disabled + eventDates : [], // specific day(s) which will be shown in a different color and using tooltips + centuryBreak : 60, // starting short year until 99 where it will be assumed to belong to the last century + currentCentury : 2000, // century to be added to 2-digit years (00 to {centuryBreak}-1) + selectAdjacentDays : false, // The calendar can show dates from adjacent month. These adjacent month dates can also be made selectable. + // popup options ('popup', 'on', 'hoverable', and show/hide callbacks are overridden) + popupOptions: { + position: 'bottom left', + lastResort: 'bottom left', + prefer: 'opposite', + hideOnScroll: false + }, + + text: { + days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'], + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + today: 'Today', + now: 'Now', + am: 'AM', + pm: 'PM', + weekNo: 'Week' + }, + + formatter: { + header: function (date, mode, settings) { + return mode === 'year' ? settings.formatter.yearHeader(date, settings) : + mode === 'month' ? settings.formatter.monthHeader(date, settings) : + mode === 'day' ? settings.formatter.dayHeader(date, settings) : + mode === 'hour' ? settings.formatter.hourHeader(date, settings) : + settings.formatter.minuteHeader(date, settings); + }, + yearHeader: function (date, settings) { + var decadeYear = Math.ceil(date.getFullYear() / 10) * 10; + return (decadeYear - 9) + ' - ' + (decadeYear + 2); + }, + monthHeader: function (date, settings) { + return date.getFullYear(); + }, + dayHeader: function (date, settings) { + var month = settings.text.months[date.getMonth()]; + var year = date.getFullYear(); + return month + ' ' + year; + }, + hourHeader: function (date, settings) { + return settings.formatter.date(date, settings); + }, + minuteHeader: function (date, settings) { + return settings.formatter.date(date, settings); + }, + dayColumnHeader: function (day, settings) { + return settings.text.days[day]; + }, + datetime: function (date, settings) { + if (!date) { + return ''; + } + var day = settings.type === 'time' ? '' : settings.formatter.date(date, settings); + var time = settings.type.indexOf('time') < 0 ? '' : settings.formatter.time(date, settings, false); + var separator = settings.type === 'datetime' ? ' ' : ''; + return day + separator + time; + }, + date: function (date, settings) { + if (!date) { + return ''; + } + var day = date.getDate(); + var month = settings.text.months[date.getMonth()]; + var year = date.getFullYear(); + return settings.type === 'year' ? year : + settings.type === 'month' ? month + ' ' + year : + (settings.monthFirst ? month + ' ' + day : day + ' ' + month) + ', ' + year; + }, + time: function (date, settings, forCalendar) { + if (!date) { + return ''; + } + var hour = date.getHours(); + var minute = date.getMinutes(); + var ampm = ''; + if (settings.ampm) { + ampm = ' ' + (hour < 12 ? settings.text.am : settings.text.pm); + hour = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour; + } + return hour + ':' + (minute < 10 ? '0' : '') + minute + ampm; + }, + today: function (settings) { + return settings.type === 'date' ? settings.text.today : settings.text.now; + }, + cell: function (cell, date, cellOptions) { + } + }, + + parser: { + date: function (text, settings) { + if (text instanceof Date) { + return text; + } + if (!text) { + return null; + } + text = String(text).trim(); + if (text.length === 0) { + return null; + } + if(text.match(/^[0-9]{4}[\/\-\.][0-9]{2}[\/\-\.][0-9]{2}$/)){ + text = text.replace(/[\/\-\.]/g,'/') + ' 00:00:00'; + } + // Reverse date and month in some cases + text = settings.monthFirst || !text.match(/^[0-9]{2}[\/\-\.]/) ? text : text.replace(/[\/\-\.]/g,'/').replace(/([0-9]+)\/([0-9]+)/,'$2/$1'); + var textDate = new Date(text); + var numberOnly = text.match(/^[0-9]+$/) !== null; + if(!numberOnly && !isNaN(textDate.getDate())) { + return textDate; + } + text = text.toLowerCase(); + + var i, j, k; + var minute = -1, hour = -1, day = -1, month = -1, year = -1; + var isAm = undefined; + + var isTimeOnly = settings.type === 'time'; + var isDateOnly = settings.type.indexOf('time') < 0; + + var words = text.split(settings.regExp.dateWords), word; + var numbers = text.split(settings.regExp.dateNumbers), number; + + var parts; + var monthString; + + if (!isDateOnly) { + //am/pm + isAm = $.inArray(settings.text.am.toLowerCase(), words) >= 0 ? true : + $.inArray(settings.text.pm.toLowerCase(), words) >= 0 ? false : undefined; + + //time with ':' + for (i = 0; i < numbers.length; i++) { + number = numbers[i]; + if (number.indexOf(':') >= 0) { + if (hour < 0 || minute < 0) { + parts = number.split(':'); + for (k = 0; k < Math.min(2, parts.length); k++) { + j = parseInt(parts[k]); + if (isNaN(j)) { + j = 0; + } + if (k === 0) { + hour = j % 24; + } else { + minute = j % 60; + } + } + } + numbers.splice(i, 1); + } + } + } + + if (!isTimeOnly) { + //textual month + for (i = 0; i < words.length; i++) { + word = words[i]; + if (word.length <= 0) { + continue; + } + for (j = 0; j < settings.text.months.length; j++) { + monthString = settings.text.months[j]; + monthString = monthString.substring(0, word.length).toLowerCase(); + if (monthString === word) { + month = j + 1; + break; + } + } + if (month >= 0) { + break; + } + } + + //year > settings.centuryBreak + for (i = 0; i < numbers.length; i++) { + j = parseInt(numbers[i]); + if (isNaN(j)) { + continue; + } + if (j >= settings.centuryBreak && i === numbers.length-1) { + if (j <= 99) { + j += settings.currentCentury - 100; + } + year = j; + numbers.splice(i, 1); + break; + } + } + + //numeric month + if (month < 0) { + for (i = 0; i < numbers.length; i++) { + k = i > 1 || settings.monthFirst ? i : i === 1 ? 0 : 1; + j = parseInt(numbers[k]); + if (isNaN(j)) { + continue; + } + if (1 <= j && j <= 12) { + month = j; + numbers.splice(k, 1); + break; + } + } + } + + //day + for (i = 0; i < numbers.length; i++) { + j = parseInt(numbers[i]); + if (isNaN(j)) { + continue; + } + if (1 <= j && j <= 31) { + day = j; + numbers.splice(i, 1); + break; + } + } + + //year <= settings.centuryBreak + if (year < 0) { + for (i = numbers.length - 1; i >= 0; i--) { + j = parseInt(numbers[i]); + if (isNaN(j)) { + continue; + } + if (j <= 99) { + j += settings.currentCentury; + } + year = j; + numbers.splice(i, 1); + break; + } + } + } + + if (!isDateOnly) { + //hour + if (hour < 0) { + for (i = 0; i < numbers.length; i++) { + j = parseInt(numbers[i]); + if (isNaN(j)) { + continue; + } + if (0 <= j && j <= 23) { + hour = j; + numbers.splice(i, 1); + break; + } + } + } + + //minute + if (minute < 0) { + for (i = 0; i < numbers.length; i++) { + j = parseInt(numbers[i]); + if (isNaN(j)) { + continue; + } + if (0 <= j && j <= 59) { + minute = j; + numbers.splice(i, 1); + break; + } + } + } + } + + if (minute < 0 && hour < 0 && day < 0 && month < 0 && year < 0) { + return null; + } + + if (minute < 0) { + minute = 0; + } + if (hour < 0) { + hour = 0; + } + if (day < 0) { + day = 1; + } + if (month < 0) { + month = 1; + } + if (year < 0) { + year = new Date().getFullYear(); + } + + if (isAm !== undefined) { + if (isAm) { + if (hour === 12) { + hour = 0; + } + } else if (hour < 12) { + hour += 12; + } + } + + var date = new Date(year, month - 1, day, hour, minute); + if (date.getMonth() !== month - 1 || date.getFullYear() !== year) { + //month or year don't match up, switch to last day of the month + date = new Date(year, month, 0, hour, minute); + } + return isNaN(date.getTime()) ? null : date; + } + }, + + // callback before date is changed, return false to cancel the change + onBeforeChange: function (date, text, mode) { + return true; + }, + + // callback when date changes + onChange: function (date, text, mode) { + }, + + // callback before show animation, return false to prevent show + onShow: function () { + }, + + // callback after show animation + onVisible: function () { + }, + + // callback before hide animation, return false to prevent hide + onHide: function () { + }, + + // callback after hide animation + onHidden: function () { + }, + + // callback before item is selected, return false to prevent selection + onSelect: function (date, mode) { + }, + + // is the given date disabled? + isDisabled: function (date, mode) { + return false; + }, + + selector: { + popup: '.ui.popup', + input: 'input', + activator: 'input', + append: '.inline.field,.inline.fields' + }, + + regExp: { + dateWords: /[^A-Za-z\u00C0-\u024F]+/g, + dateNumbers: /[^\d:]+/g + }, + + error: { + popup: 'UI Popup, a required component is not included in this page', + method: 'The method you called is not defined.' + }, + + className: { + calendar: 'calendar', + active: 'active', + popup: 'ui popup', + grid: 'ui equal width grid', + column: 'column', + table: 'ui celled center aligned unstackable table', + inverted: 'inverted', + prev: 'prev link', + next: 'next link', + prevIcon: 'chevron left icon', + nextIcon: 'chevron right icon', + link: 'link', + cell: 'link', + disabledCell: 'disabled', + weekCell: 'disabled', + adjacentCell: 'adjacent', + activeCell: 'active', + rangeCell: 'range', + focusCell: 'focus', + todayCell: 'today', + today: 'today link', + disabled: 'disabled' + }, + + metadata: { + date: 'date', + focusDate: 'focusDate', + startDate: 'startDate', + endDate: 'endDate', + minDate: 'minDate', + maxDate: 'maxDate', + mode: 'mode', + type: 'type', + monthOffset: 'monthOffset', + message: 'message', + class: 'class', + inverted: 'inverted', + variation: 'variation', + position: 'position', + month: 'month', + year: 'year' + }, + + eventClass: 'blue' +}; + +})(jQuery, window, document); diff --git a/semantic/src/definitions/modules/calendar.less b/semantic/src/definitions/modules/calendar.less new file mode 100644 index 0000000..aaa7f11 --- /dev/null +++ b/semantic/src/definitions/modules/calendar.less @@ -0,0 +1,195 @@ +/*! + * # Fomantic-UI - Calendar + * http://github.com/fomantic/Fomantic-UI/ + * + * + * Released under the MIT license + * http://opensource.org/licenses/MIT + * + */ + +/******************************* + Theme +*******************************/ + +@type : 'module'; +@element : 'calendar'; + +@import (multiple) '../../theme.config'; + +/******************************* + Popup +*******************************/ + +.ui.calendar .ui.popup { + max-width: none; + padding: 0; + border: none; + user-select: none; +} + +/******************************* + Calendar +*******************************/ + +.ui.calendar .calendar:focus { + outline: 0; +} + +/******************************* + Grid +*******************************/ + +.ui.calendar .ui.popup .ui.grid { + display: block; + white-space: nowrap; +} + +.ui.calendar .ui.popup .ui.grid > .column { + width: auto; +} + +/******************************* + Table +*******************************/ + +.ui.calendar .ui.table.year, +.ui.calendar .ui.table.month, +.ui.calendar .ui.table.minute { + min-width: 15em; +} + +.ui.calendar .ui.table.day { + min-width: 18em; +} + +.ui.calendar .ui.table.day.andweek { + min-width: 22em; +} + +.ui.calendar .ui.table.hour { + min-width: 20em; +} + +.ui.calendar .ui.table tr th, +.ui.calendar .ui.table tr td { + padding: 0.5em; + white-space: nowrap; +} + +.ui.calendar .ui.table tr th { + border-left: none; +} + +.ui.calendar .ui.table tr th i.icon { + margin: 0; +} + +.ui.calendar .ui.table tr:first-child th { + position: relative; + padding-left: 0; + padding-right: 0; +} + +.ui.calendar .ui.table.day tr:first-child th { + border: none; +} + +.ui.calendar .ui.table.day tr:nth-child(2) th { + padding-top: 0.2em; + padding-bottom: 0.3em; +} + +.ui.calendar .ui.table tr td { + padding-left: 0.1em; + padding-right: 0.1em; +} + +.ui.calendar .ui.table tr .link { + cursor: pointer; +} + +.ui.calendar .ui.table tr .prev.link { + width: 14.28571429%; + position: absolute; + left: 0; +} + +.ui.calendar .ui.table tr .next.link { + width: 14.28571429%; + position: absolute; + right: 0; +} + +.ui.ui.calendar .ui.table tr .disabled { + pointer-events: auto; + cursor: default; + color: @disabledTextColor; +} + +.ui.calendar .ui.table tr .adjacent:not(.disabled) { + color: @adjacentTextColor; + background: @adjacentBackground; +} + +/*-------------- + States +---------------*/ + +.ui.calendar .ui.table tr td.today { + font-weight: @todayFontWeight; +} + +.ui.calendar .ui.table tr td.range { + background: @rangeBackground; + color: @rangeTextColor; + box-shadow: @rangeBoxShadow; +} + +.ui.calendar:not(.disabled) .calendar:focus .ui.table tbody tr td.focus, +.ui.calendar:not(.disabled) .calendar.active .ui.table tbody tr td.focus { + box-shadow: @focusBoxShadow; +} + +& when (@variationCalendarInverted) { + .ui.inverted.calendar .ui.table.inverted tr td.range { + background: @rangeInvertedBackground; + color: @rangeInvertedTextColor; + box-shadow: @rangeInvertedBoxShadow; + } + + .ui.inverted.calendar:not(.disabled) .calendar:focus .ui.table.inverted tbody tr td.focus, + .ui.inverted.calendar:not(.disabled) .calendar.active .ui.table.inverted tbody tr td.focus { + box-shadow: @focusInvertedBoxShadow; + } + .ui.inverted.calendar .ui.inverted.table tr .disabled { + color: @invertedDisabledTextColor; + } + + .ui.inverted.calendar .ui.inverted.table tr .adjacent:not(.disabled) { + color: @adjacentInvertedTextColor; + background: @adjacentInvertedBackground; + } +} + +/******************************* + States +*******************************/ + +& when (@variationCalendarDisabled) { + /*-------------------- + Disabled + ---------------------*/ + + .ui.disabled.calendar { + opacity: @disabledOpacity; + } + + .ui.disabled.calendar > .input, + .ui.disabled.calendar .ui.table tr .link { + pointer-events: none; + } +} + + +.loadUIOverrides(); diff --git a/semantic/src/definitions/modules/checkbox.js b/semantic/src/definitions/modules/checkbox.js new file mode 100644 index 0000000..c5540ba --- /dev/null +++ b/semantic/src/definitions/modules/checkbox.js @@ -0,0 +1,876 @@ +/*! + * # Fomantic-UI - Checkbox + * http://github.com/fomantic/Fomantic-UI/ + * + * + * Released under the MIT license + * http://opensource.org/licenses/MIT + * + */ + +;(function ($, window, document, undefined) { + +'use strict'; + +$.isFunction = $.isFunction || function(obj) { + return typeof obj === "function" && typeof obj.nodeType !== "number"; +}; + +window = (typeof window != 'undefined' && window.Math == Math) + ? window + : (typeof self != 'undefined' && self.Math == Math) + ? self + : Function('return this')() +; + +$.fn.checkbox = function(parameters) { + var + $allModules = $(this), + moduleSelector = $allModules.selector || '', + + time = new Date().getTime(), + performance = [], + + query = arguments[0], + methodInvoked = (typeof query == 'string'), + queryArguments = [].slice.call(arguments, 1), + returnedValue + ; + + $allModules + .each(function() { + var + settings = $.extend(true, {}, $.fn.checkbox.settings, parameters), + + className = settings.className, + namespace = settings.namespace, + selector = settings.selector, + error = settings.error, + + eventNamespace = '.' + namespace, + moduleNamespace = 'module-' + namespace, + + $module = $(this), + $label = $(this).children(selector.label), + $input = $(this).children(selector.input), + input = $input[0], + + initialLoad = false, + shortcutPressed = false, + instance = $module.data(moduleNamespace), + + observer, + element = this, + module + ; + + module = { + + initialize: function() { + module.verbose('Initializing checkbox', settings); + + module.create.label(); + module.bind.events(); + + module.set.tabbable(); + module.hide.input(); + + module.observeChanges(); + module.instantiate(); + module.setup(); + }, + + instantiate: function() { + module.verbose('Storing instance of module', module); + instance = module; + $module + .data(moduleNamespace, module) + ; + }, + + destroy: function() { + module.verbose('Destroying module'); + module.unbind.events(); + module.show.input(); + $module.removeData(moduleNamespace); + }, + + fix: { + reference: function() { + if( $module.is(selector.input) ) { + module.debug('Behavior called on adjusting invoked element'); + $module = $module.closest(selector.checkbox); + module.refresh(); + } + } + }, + + setup: function() { + module.set.initialLoad(); + if( module.is.indeterminate() ) { + module.debug('Initial value is indeterminate'); + module.indeterminate(); + } + else if( module.is.checked() ) { + module.debug('Initial value is checked'); + module.check(); + } + else { + module.debug('Initial value is unchecked'); + module.uncheck(); + } + module.remove.initialLoad(); + }, + + refresh: function() { + $label = $module.children(selector.label); + $input = $module.children(selector.input); + input = $input[0]; + }, + + hide: { + input: function() { + module.verbose('Modifying z-index to be unselectable'); + $input.addClass(className.hidden); + } + }, + show: { + input: function() { + module.verbose('Modifying z-index to be selectable'); + $input.removeClass(className.hidden); + } + }, + + observeChanges: function() { + if('MutationObserver' in window) { + observer = new MutationObserver(function(mutations) { + module.debug('DOM tree modified, updating selector cache'); + module.refresh(); + }); + observer.observe(element, { + childList : true, + subtree : true + }); + module.debug('Setting up mutation observer', observer); + } + }, + + attachEvents: function(selector, event) { + var + $element = $(selector) + ; + event = $.isFunction(module[event]) + ? module[event] + : module.toggle + ; + if($element.length > 0) { + module.debug('Attaching checkbox events to element', selector, event); + $element + .on('click' + eventNamespace, event) + ; + } + else { + module.error(error.notFound); + } + }, + + preventDefaultOnInputTarget: function() { + if(typeof event !== 'undefined' && event !== null && $(event.target).is(selector.input)) { + module.verbose('Preventing default check action after manual check action'); + event.preventDefault(); + } + }, + + event: { + change: function(event) { + if( !module.should.ignoreCallbacks() ) { + settings.onChange.call(input); + } + }, + click: function(event) { + var + $target = $(event.target) + ; + if( $target.is(selector.input) ) { + module.verbose('Using default check action on initialized checkbox'); + return; + } + if( $target.is(selector.link) ) { + module.debug('Clicking link inside checkbox, skipping toggle'); + return; + } + module.toggle(); + $input.focus(); + event.preventDefault(); + }, + keydown: function(event) { + var + key = event.which, + keyCode = { + enter : 13, + space : 32, + escape : 27, + left : 37, + up : 38, + right : 39, + down : 40 + } + ; + + var r = module.get.radios(), + rIndex = r.index($module), + rLen = r.length, + checkIndex = false; + + if(key == keyCode.left || key == keyCode.up) { + checkIndex = (rIndex === 0 ? rLen : rIndex) - 1; + } else if(key == keyCode.right || key == keyCode.down) { + checkIndex = rIndex === rLen-1 ? 0 : rIndex+1; + } + + if (!module.should.ignoreCallbacks() && checkIndex !== false) { + if(settings.beforeUnchecked.apply(input)===false) { + module.verbose('Option not allowed to be unchecked, cancelling key navigation'); + return false; + } + if (settings.beforeChecked.apply($(r[checkIndex]).children(selector.input)[0])===false) { + module.verbose('Next option should not allow check, cancelling key navigation'); + return false; + } + } + + if(key == keyCode.escape) { + module.verbose('Escape key pressed blurring field'); + $input.blur(); + shortcutPressed = true; + } + else if(!event.ctrlKey && ( key == keyCode.space || (key == keyCode.enter && settings.enableEnterKey)) ) { + module.verbose('Enter/space key pressed, toggling checkbox'); + module.toggle(); + shortcutPressed = true; + } + else { + shortcutPressed = false; + } + }, + keyup: function(event) { + if(shortcutPressed) { + event.preventDefault(); + } + } + }, + + check: function() { + if( !module.should.allowCheck() ) { + return; + } + module.debug('Checking checkbox', $input); + module.set.checked(); + if( !module.should.ignoreCallbacks() ) { + settings.onChecked.call(input); + module.trigger.change(); + } + module.preventDefaultOnInputTarget(); + }, + + uncheck: function() { + if( !module.should.allowUncheck() ) { + return; + } + module.debug('Unchecking checkbox'); + module.set.unchecked(); + if( !module.should.ignoreCallbacks() ) { + settings.onUnchecked.call(input); + module.trigger.change(); + } + module.preventDefaultOnInputTarget(); + }, + + indeterminate: function() { + if( module.should.allowIndeterminate() ) { + module.debug('Checkbox is already indeterminate'); + return; + } + module.debug('Making checkbox indeterminate'); + module.set.indeterminate(); + if( !module.should.ignoreCallbacks() ) { + settings.onIndeterminate.call(input); + module.trigger.change(); + } + }, + + determinate: function() { + if( module.should.allowDeterminate() ) { + module.debug('Checkbox is already determinate'); + return; + } + module.debug('Making checkbox determinate'); + module.set.determinate(); + if( !module.should.ignoreCallbacks() ) { + settings.onDeterminate.call(input); + module.trigger.change(); + } + }, + + enable: function() { + if( module.is.enabled() ) { + module.debug('Checkbox is already enabled'); + return; + } + module.debug('Enabling checkbox'); + module.set.enabled(); + if( !module.should.ignoreCallbacks() ) { + settings.onEnable.call(input); + // preserve legacy callbacks + settings.onEnabled.call(input); + module.trigger.change(); + } + }, + + disable: function() { + if( module.is.disabled() ) { + module.debug('Checkbox is already disabled'); + return; + } + module.debug('Disabling checkbox'); + module.set.disabled(); + if( !module.should.ignoreCallbacks() ) { + settings.onDisable.call(input); + // preserve legacy callbacks + settings.onDisabled.call(input); + module.trigger.change(); + } + }, + + get: { + radios: function() { + var + name = module.get.name() + ; + return $('input[name="' + name + '"]').closest(selector.checkbox); + }, + otherRadios: function() { + return module.get.radios().not($module); + }, + name: function() { + return $input.attr('name'); + } + }, + + is: { + initialLoad: function() { + return initialLoad; + }, + radio: function() { + return ($input.hasClass(className.radio) || $input.attr('type') == 'radio'); + }, + indeterminate: function() { + return $input.prop('indeterminate') !== undefined && $input.prop('indeterminate'); + }, + checked: function() { + return $input.prop('checked') !== undefined && $input.prop('checked'); + }, + disabled: function() { + return $input.prop('disabled') !== undefined && $input.prop('disabled'); + }, + enabled: function() { + return !module.is.disabled(); + }, + determinate: function() { + return !module.is.indeterminate(); + }, + unchecked: function() { + return !module.is.checked(); + } + }, + + should: { + allowCheck: function() { + if(module.is.determinate() && module.is.checked() && !module.is.initialLoad() ) { + module.debug('Should not allow check, checkbox is already checked'); + return false; + } + if(!module.should.ignoreCallbacks() && settings.beforeChecked.apply(input) === false) { + module.debug('Should not allow check, beforeChecked cancelled'); + return false; + } + return true; + }, + allowUncheck: function() { + if(module.is.determinate() && module.is.unchecked() && !module.is.initialLoad() ) { + module.debug('Should not allow uncheck, checkbox is already unchecked'); + return false; + } + if(!module.should.ignoreCallbacks() && settings.beforeUnchecked.apply(input) === false) { + module.debug('Should not allow uncheck, beforeUnchecked cancelled'); + return false; + } + return true; + }, + allowIndeterminate: function() { + if(module.is.indeterminate() && !module.is.initialLoad() ) { + module.debug('Should not allow indeterminate, checkbox is already indeterminate'); + return false; + } + if(!module.should.ignoreCallbacks() && settings.beforeIndeterminate.apply(input) === false) { + module.debug('Should not allow indeterminate, beforeIndeterminate cancelled'); + return false; + } + return true; + }, + allowDeterminate: function() { + if(module.is.determinate() && !module.is.initialLoad() ) { + module.debug('Should not allow determinate, checkbox is already determinate'); + return false; + } + if(!module.should.ignoreCallbacks() && settings.beforeDeterminate.apply(input) === false) { + module.debug('Should not allow determinate, beforeDeterminate cancelled'); + return false; + } + return true; + }, + ignoreCallbacks: function() { + return (initialLoad && !settings.fireOnInit); + } + }, + + can: { + change: function() { + return !( $module.hasClass(className.disabled) || $module.hasClass(className.readOnly) || $input.prop('disabled') || $input.prop('readonly') ); + }, + uncheck: function() { + return (typeof settings.uncheckable === 'boolean') + ? settings.uncheckable + : !module.is.radio() + ; + } + }, + + set: { + initialLoad: function() { + initialLoad = true; + }, + checked: function() { + module.verbose('Setting class to checked'); + $module + .removeClass(className.indeterminate) + .addClass(className.checked) + ; + if( module.is.radio() ) { + module.uncheckOthers(); + } + if(!module.is.indeterminate() && module.is.checked()) { + module.debug('Input is already checked, skipping input property change'); + return; + } + module.verbose('Setting state to checked', input); + $input + .prop('indeterminate', false) + .prop('checked', true) + ; + }, + unchecked: function() { + module.verbose('Removing checked class'); + $module + .removeClass(className.indeterminate) + .removeClass(className.checked) + ; + if(!module.is.indeterminate() && module.is.unchecked() ) { + module.debug('Input is already unchecked'); + return; + } + module.debug('Setting state to unchecked'); + $input + .prop('indeterminate', false) + .prop('checked', false) + ; + }, + indeterminate: function() { + module.verbose('Setting class to indeterminate'); + $module + .addClass(className.indeterminate) + ; + if( module.is.indeterminate() ) { + module.debug('Input is already indeterminate, skipping input property change'); + return; + } + module.debug('Setting state to indeterminate'); + $input + .prop('indeterminate', true) + ; + }, + determinate: function() { + module.verbose('Removing indeterminate class'); + $module + .removeClass(className.indeterminate) + ; + if( module.is.determinate() ) { + module.debug('Input is already determinate, skipping input property change'); + return; + } + module.debug('Setting state to determinate'); + $input + .prop('indeterminate', false) + ; + }, + disabled: function() { + module.verbose('Setting class to disabled'); + $module + .addClass(className.disabled) + ; + if( module.is.disabled() ) { + module.debug('Input is already disabled, skipping input property change'); + return; + } + module.debug('Setting state to disabled'); + $input + .prop('disabled', 'disabled') + ; + }, + enabled: function() { + module.verbose('Removing disabled class'); + $module.removeClass(className.disabled); + if( module.is.enabled() ) { + module.debug('Input is already enabled, skipping input property change'); + return; + } + module.debug('Setting state to enabled'); + $input + .prop('disabled', false) + ; + }, + tabbable: function() { + module.verbose('Adding tabindex to checkbox'); + if( $input.attr('tabindex') === undefined) { + $input.attr('tabindex', 0); + } + } + }, + + remove: { + initialLoad: function() { + initialLoad = false; + } + }, + + trigger: { + change: function() { + var + inputElement = $input[0] + ; + if(inputElement) { + var events = document.createEvent('HTMLEvents'); + module.verbose('Triggering native change event'); + events.initEvent('change', true, false); + inputElement.dispatchEvent(events); + } + } + }, + + + create: { + label: function() { + if($input.prevAll(selector.label).length > 0) { + $input.prev(selector.label).detach().insertAfter($input); + module.debug('Moving existing label', $label); + } + else if( !module.has.label() ) { + $label = $('