TabbedView.JS

From disqus.com, 5 Days ago, written in JavaScript, viewed 3 times.
URL https://pastebin.freepbx.org/view/e88e0f78 Embed
Download Paste or View Raw
  1. define('home/views/common/TabbedView',[
  2.     'jquery',
  3.     'underscore',
  4.     'backbone-marionette',
  5.  
  6.     'core/utils/metatags',
  7.     'core/bus',
  8.     'home/utils/trackingUtils',
  9.     'home/utils/navigationUtils',
  10. ], function (
  11.     $,
  12.     _,
  13.     Marionette,
  14.  
  15.     metatags,
  16.     bus,
  17.     trackingUtils,
  18.     navigationUtils
  19. ) {
  20.     'use strict';
  21.  
  22.     /**
  23.      * Not intended to be instantiated.
  24.      *
  25.      * Parent class for views with multiple "tabs" of content that can be switched.
  26.      *
  27.      * Provides region for a content area that shows the active content.
  28.      *
  29.      * Provides listeners/handlers for clicks that switch the tab content,
  30.      * and optionally update the url without causing a backbone router navigation.
  31.      *
  32.      * ex:
  33.  == JavaScript ==
  34.         var TwoTabs = TabbedView.extend({
  35.             template: 'twotabs',
  36.  
  37.             // must provide. used by base class
  38.             getTabView(tab) {
  39.                 switch(tab) {
  40.                     case 'one':
  41.                         return new View({name: 'one'});
  42.                     case 'two':
  43.                         return new View({name: 'two'});
  44.                 }
  45.             }
  46.         });
  47.  
  48.  == HTML/Handlebars ==
  49.         {{! 'twotabs' template }}
  50.         <nav>
  51.             {{! including href in conjunction with switch-tab will use pushState to update the browser address bar }}
  52.             <a href="/home/area/one" data-action="switch-tab" {{! no data-tab attr means this triggers the default tab }}>One</a>
  53.             <a href="/home/area/two" data-action="switch-tab" data-tab="two">Two</a>
  54.         </nav>
  55.         {{! must have data-role=content-area for loading tab content }}
  56.         <section data-role="content-area"></section>
  57.  
  58.  == CSS ==
  59.         .active {
  60.             // these rules will be applied to the tab currently selected
  61.          }
  62.      */
  63.     var TabbedView = Marionette.Layout.extend({
  64.         // Must override, either a function that returns a string, or the
  65.         // string itself, that is the name of tab that's active by default
  66.         defaultTab: undefined,
  67.  
  68.         // Mark this view's top element as a tabbed view so that we can determine
  69.         // when a tab belongs to a nested tabbed view
  70.         attributes: {
  71.             'data-view-type': 'tabbed',
  72.         },
  73.  
  74.         /**
  75.          * Must override.
  76.          * Returns a view instance to show when the given tab is active.
  77.          * @param {string} [activeTab] - The name of the active tab
  78.          */
  79.         getTabView: function () {
  80.             throw new Error('Not implemented');
  81.         },
  82.  
  83.         /**
  84.          * Can override in order to specify the section to be passed on
  85.          * jester event tracking.
  86.          * @param {string} [activeTab]
  87.          * @returns {string} The section to send with jester events, or null
  88.          *                  to pass defaults.
  89.          */
  90.         getTrackingSection: function () {
  91.             return null;
  92.         },
  93.  
  94.         // Child view's template should define below element(s)
  95.         regions: {
  96.             contentRegion: '[data-role=content-area]',
  97.         },
  98.  
  99.         events: {
  100.             'click [data-action=switch-tab]': 'switchTab',
  101.         },
  102.  
  103.         initialize: function (options) {
  104.             options = options || {};
  105.             this.activeTab = options.activeTab;
  106.             this.isModule = options.isModule;
  107.             this.setTrackingSection();
  108.         },
  109.  
  110.         switchTab: function (evt) {
  111.             if (!evt)
  112.                 return false;
  113.  
  114.             // Don't allow tab changes in nested tabbed views propagate to parent
  115.             // tabbed views.
  116.             evt.preventDefault();
  117.             evt.stopPropagation();
  118.  
  119.             var requestedTab = $(evt.currentTarget).data('tab');
  120.  
  121.             this.toggleDropdown();
  122.  
  123.             // User clicked the tab that is currently displayed: so do nothing
  124.             if (requestedTab === this.activeTab)
  125.                 return;
  126.  
  127.             this.activeTab = requestedTab || _.result(this, 'defaultTab');
  128.  
  129.             // Find an anchor inside the tab, whether the user clicked on an element inside
  130.             // the anchor, or on the top level tab element that contains the anchor.
  131.             var $tab = $(evt.target).closest('[data-action=switch-tab]');
  132.             var $anchor = $tab.find('a[href]').addBack('a[href]');
  133.  
  134.             // If href specified, update the url to represent the new href
  135.             // (without triggering route handler)
  136.             // Do this before updating the content of the tab so that any events triggered
  137.             // during the showing of the content will have the correct url
  138.             if ($anchor.length)
  139.                 navigationUtils.navigate($anchor[0]);
  140.  
  141.             this.updateTab();
  142.         },
  143.  
  144.         toggleDropdown: function () {
  145.             var navItem = this.$('.nav__item');
  146.             if (navItem.length > 0)
  147.                 navItem.toggleClass('dropdown-open');
  148.         },
  149.  
  150.         updateTab: function () {
  151.             if (!this.activeTab)
  152.                 this.activeTab = _.result(this, 'defaultTab');
  153.  
  154.             var activeTab = this.activeTab;
  155.             var newView = this.getTabView(activeTab);
  156.  
  157.             if (!newView) {
  158.                 this.trigger('badTab');
  159.                 activeTab = this.activeTab = _.result(this, 'defaultTab');
  160.                 newView = this.getTabView(activeTab);
  161.             }
  162.  
  163.             this.setTrackingSection();
  164.  
  165.             this.updateTabContent(newView);
  166.  
  167.             this.updateTabClasses();
  168.  
  169.             this.trigger('change:activeTab', activeTab);
  170.             bus.trigger('viewTab');
  171.         },
  172.  
  173.         /**
  174.          * Returns the elements within this view for changing tabs. Excludes those
  175.          * used for changing tabs in a nested TabbedView.
  176.          * @returns {jQuery}
  177.          */
  178.         getTabs: function () {
  179.             // Exclude tabs from a TabbedView nested within this TabbedView
  180.             var $allTabs = this.$('[data-action=switch-tab]');
  181.             var $nestedTabs = this.$('[data-view-type=tabbed] [data-action=switch-tab]');
  182.  
  183.             return $allTabs.not($nestedTabs);
  184.         },
  185.  
  186.         updateTabClasses: function () {
  187.             if (!this.activeTab)
  188.                 this.activeTab = _.result(this, 'defaultTab');
  189.  
  190.             // Update the tabs to show which one is currently active
  191.             var $tabs = this.getTabs();
  192.             $tabs.filter('.active').removeClass('active');
  193.             $tabs.filter('[data-tab="' + this.activeTab + '"]').addClass('active');
  194.         },
  195.  
  196.         updateTabContent: function (newView) {
  197.             var oldView = this.contentRegion.currentView;
  198.  
  199.             if (oldView) {
  200.                 // Prevent oldView from being closed, so that there isn't a time between closing
  201.                 // the old view and adding the new view, which causes a page jump. Will manually
  202.                 // close oldView later.
  203.                 oldView.onBeforeClose = function () {
  204.                     return false;
  205.                 };
  206.  
  207.                 // If this is a full-page view, ensure that the new view is tall enough so that it
  208.                 // will fill the current viewport, otherwise the page will get shorter and the
  209.                 // scrollbar will jump up, causing a jarring ux, unless the page is already
  210.                 // scrolled to top and then the minHeigh is not necessary.
  211.                 if (!this.isModule) {
  212.                     var scrollTop = $(window).scrollTop();
  213.  
  214.                     if (scrollTop) {
  215.                         var minHeight = scrollTop + $(window).height() - oldView.$el.offset().top;
  216.                         newView.$el.css('minHeight', minHeight);
  217.                     }
  218.                 }
  219.             }
  220.  
  221.             this.contentRegion.show(newView);
  222.  
  223.             // Set the metatags and title for the page. `getMetaAttrs` returns
  224.             // either a promise or a truthy object. If the view does not have a
  225.             // `getMetaAttrs` method, we default to an empty dictionary which
  226.             // resolves the $.when.
  227.             if (this.getMetaAttrs)
  228.                 $.when(this.getMetaAttrs()).then(metatags.set);
  229.  
  230.             if (oldView) {
  231.                 // Now that the newView is in the dom, close the oldView.
  232.                 oldView.onBeforeClose = null;
  233.                 oldView.close();
  234.             }
  235.         },
  236.  
  237.         onDomRefresh: function () {
  238.             // Don't bother creating views to fill in the regions if the regions don't
  239.             // exist. This occurs when showing the fetching icon.
  240.  
  241.             if (this.$(this.contentRegion.el).length)
  242.                 this.updateTab();
  243.         },
  244.  
  245.         setTrackingSection: function () {
  246.             trackingUtils.setSection(
  247.                 this.getTrackingSection(this.activeTab) || _.result(this, 'defaultTab')
  248.             );
  249.         },
  250.  
  251.     });
  252.  
  253.     return TabbedView;
  254. });
  255.  
  256. // https://c.disquscdn.com/next/home/js/views/common/TabbedView.js

Replies to TabbedView.JS rss

Title Name Language When
withThreadSharing.Js disqus.com javascript 5 Days ago.

Reply to "TabbedView.JS"

Here you can reply to the paste above