net-history/js/timeliner.js

Summary

Maintainability
D
1 day
Test Coverage
/*
* Timeliner.js
* @version        2.2
* @copyright    Tarek Anandan (http://www.technotarek.com)
*/
;(function($) {

        $.timeliner = function(options) {
            if ($.timeliners == null) {
                $.timeliners = { options: [] };
                $.timeliners.options.push(options);
            }
            else {
                $.timeliners.options.push(options);
            }
            $(document).ready(function() {
                for (var i=0; i<$.timeliners.options.length; i++) {
                    startTimeliner($.timeliners.options[i]);
                }
            });
        }

        function startTimeliner(options) {
            var settings = {
                timelineContainer: options['timelineContainer'] || '#timeline',
                // Container for the element holding the entire timeline (e.g. a DIV)
                // value: ID or class selector
                // default: #timeline
                // note: must be unique for each timeline on page

                timelineSection: options['timelineSection'] || '.timeline-wrapper',
                // Wrapper that surrounds a time and series of events (e.g., all of the events under a year on the timeline)
                // value: class selector
                // default: .timeline-wrapper
                // note: changing this selector from the default will require modifications to the CSS file in order to retain default styling

                timelineSectionMarker: options['timelineSectionMarker'] || '.timeline-time',
                // Class selector applied to each major item on the timeline, such as each year
                // value: class selector
                // default: .timeline-time

                timelineTriggerContainer: options['timelineTriggerContainer'] || '.timeline-series',
                // Wrapper surrounding a series of events corresponding to the timelineSectionMarker
                // value: selector
                // default: .timeline-series
                // note: changing this selector from the default will require modifications to the CSS file in order to retain default styling

                timelineTriggerAnchor: options['timelineTriggerAnchor'] || '.timeline-event',
                // Element that is wrapped around the event's title; when clicked, expands the event and reveals its full contents
                // value: class
                // default: .timeline-event
                // note: changing this tag from the default will require modifications to the CSS file in order to retain default styling

                timelineEventContainer: options['timelineEventContainer'] || 'dt',
                // Wrapper surrounding a series of events corresponding to the timelineSectionMarker
                // value: tag or class selector
                // default: dt
                // note: When leaving this value at its default, you do not need to apply a class to the dt element if you use the plugins recommended tag structure and markup
                // note: Change this from the default, perhaps to a class like ".timeline-event", in the case that you do not want to use the plugins recommened markup structure and prefer to use anothe element (e.g, div) instead of a dt tag to mark each event within a series.
                // note: Changing this value from the default will require modifications to the CSS file in order to retain default styling

                timelineEXContent: options['timelineEXContent'] || '.timeline-event-content',
                // Element that contains the event's full content to be displayed when event is expanded, an event's expanded ID should alway be on this item
                // value: class selector
                // default: .timeline-event
                // note: changing this selector from the default will require modifications to the CSS file in order to retain default styling

                EXContentIdSuffix: options['timelineEXContentSuffix'] || 'EX',
                // ID suffix to identify expanded (aka EX) content
                // value: string
                // default: EX

                oneOpen: options['oneOpen'] || false,
                // sets whether only one item on the timeline can be open at a time. If true, other items will close when one is opened.
                // value: true | false
                // default: false
                // note: does not apply to events identified in startOpen option

                startState: options['startState'] || 'closed',
                // sets whether the timeline is initially collapsed, fully expanded, or "flat" mode
                // value: closed | open | flat
                // default: closed
                // note: setting to "open" makes the startOpen option meaningless
                // note: flat mode initally collapses the entire timeline except for the major markers
                // note: the flat state is an initial display option only -- the timeline major markers return to normal before once they've  been opened/displayed

                startOpen: options['startOpen'] || [],
                // sets the events to display expanded on page load
                // value: array of IDs of single timelineEvents (e.g., ['#event01'] or ['#event01','#event02'])
                // default: []

                baseSpeed: options['baseSpeed'] || 200,
                // sets the base speed for animation of an event
                // value: numeric
                // default: 200

                speed: options['speed'] || 4,
                // multiplier applied to the base speed that sets the speed at which an event's contents are displayed and hidden
                // value: numeric
                // default: 4

                fontOpen: options['fontOpen'] || '1.2em',
                // sets the font size of an event after it is opened
                // value: any valid CSS font-size value,
                // default: 1.2em

                fontClosed: options['fontClosed'] || '1em',
                // sets the font size of an event after it is closed
                // value: any valid CSS font-size value
                // defaults: 1em

                expandAllText: options ['expandAllText'] || '+ expand all',
                // sets the text of the expandAll selector after the timeline is fully collapsed
                // value: string
                // default: + expand all

                collapseAllText: options['collapseAllText'] || '- collapse all'
                //sets the text of the expandAll selector after the timeline is fully expanded
                // value: string
                // default: - collapse all
            };

            function openStartEvents(events) {
                // show startOpen events
                $.each(events, function(index, value) {

                    // first make sure all events in the series are visible (overriding flat mode), then show individual events per option settings
                    $(value).parents(settings.timelineTriggerContainer).show(settings.speed*settings.baseSpeed, function(){
                        openEvent($(value).find(settings.timelineTriggerAnchor),$(value+settings.EXContentIdSuffix));
                    });

                });
            }

            function openEvent(eventHeading,eventBody) {

                if(settings.startState==='flat'){
                    // if flat mode, make sure parent series is visible
                    $(eventHeading).parents(settings.timelineTriggerContainer).show();
                }

                $(eventHeading).find('a')
                    .removeClass('closed')
                    .addClass('open')
                    .animate({ fontSize: settings.fontOpen }, settings.baseSpeed);
                $(eventBody).show(settings.speed*settings.baseSpeed);

            }

            function closeEvent(eventHeading,eventBody) {

                $(eventHeading).find('a')
                    .animate({ fontSize: settings.fontClosed }, 0)
                    .removeClass('open')
                    .addClass('closed');
                $(eventBody).hide(settings.speed*settings.baseSpeed);
            }

            if ($(settings.timelineContainer).data('started')) {
                return;
                // we already initialized this timelineContainer
            } else {
                $(settings.timelineContainer).data('started', true);
                $(settings.timelineContainer+" "+".timeline-toggle").html(settings.expandAllText);
                $(settings.timelineContainer+" "+".collapseAll").html(settings.collapseAllText);

                if(settings.startState==='flat')
                {
                    // hide all series (event headings)
                    $(settings.timelineContainer+' '+settings.timelineTriggerContainer).hide();

                    openStartEvents($(settings.startOpen));

                }else if(settings.startState==='closed')
                {
                    // If startState option is set to closed, hide all the event contents; else, show fully expanded upon load

                    // Close all items
                    $(settings.timelineContainer+" "+settings.timelineEXContent).hide();

                    openStartEvents($(settings.startOpen));

                }else{

                    // Open all items
                    openEvent($(settings.timelineContainer+" "+settings.timelineTriggerContainer+" "+settings.timelineTriggerAnchor),$(settings.timelineContainer+" "+settings.timelineEXContent));

                }

                // Minor Event Click
                $(settings.timelineContainer).on("click",settings.timelineTriggerContainer+" "+settings.timelineEventContainer,function(){

                    var currentId = $(this).attr('id');

                    // if the event is currently open
                    if($(this).find('a').is('.open'))
                    {
                        closeEvent($(this),$("#"+currentId+settings.EXContentIdSuffix))

                    } else{
                    // if the event is currently closed

                        if( settings.oneOpen == true ) {
                            closeEvent($(this).parents(settings.timelineContainer).find(settings.timelineTriggerAnchor,settings.timelineTriggerContainer),$(this).parents(settings.timelineContainer).find(settings.timelineEXContent));
                        }

                        openEvent($(this),$("#"+currentId+settings.EXContentIdSuffix));

                    }

                });

                // Major Marker Click
                // Overrides the 'oneOpen' option
                $(settings.timelineContainer).on("click",settings.timelineSectionMarker,function()
                {

                    // number of minor events under this major event
                    var numEvents = $(this).parents(settings.timelineSection).find(settings.timelineTriggerContainer).length;

                    // number of minor events already open
                    var numOpen = $(this).parents(settings.timelineSection).find('.open').length;

                    // This closes other items if oneOpen is true. It looks odd if an item in the section was open. Need to improve this.
                    if( settings.oneOpen == true ) {
                        closeEvent($(this).parents(settings.timelineContainer).find(settings.timelineTriggerAnchor,settings.timelineTriggerContainer),$(this).parents(settings.timelineContainer).find(settings.timelineEXContent));
                    }

                    if(numEvents > numOpen)
                    {
                        // if there are more events available than are displayed, then fully expand all events below MajorMarker
                        openEvent($(this).parents(settings.timelineSection).find(settings.timelineTriggerAnchor,settings.timelineTriggerContainer),$(this).parents(settings.timelineSection).find(settings.timelineEXContent));
                    }else
                    {
                        closeEvent($(this).parents(settings.timelineSection).find(settings.timelineTriggerContainer),$(this).parents(settings.timelineSection).find(settings.timelineEXContent));
                    }
                });

                // All Markers/Events
                var el = settings.timelineContainer+" "+".timeline-toggle";
                $(el).click(function()
                {
                    if($(el).hasClass('expanded'))
                    {

                        closeEvent($(el).parents(settings.timelineContainer).find(settings.timelineTriggerAnchor,settings.timelineTriggerContainer),$(el).parents(settings.timelineContainer).find(settings.timelineEXContent));
                        $(el).removeClass('expanded').html(settings.expandAllText);

                    } else{

                        openEvent($(el).parents(settings.timelineContainer).find(settings.timelineTriggerAnchor,settings.timelineTriggerContainer),$(el).parents(settings.timelineContainer).find(settings.timelineEXContent));
                        $(el).addClass('expanded').html(settings.collapseAllText);


                    }
                });
            }
        };

})(jQuery);