Advertisement
Guest User

Untitled

a guest
Jul 11th, 2017
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5 8.14 KB | None | 0 0
  1. <div class-rtabs {{yield extra-attributes}}>
  2.   <div class-tab-window {{#if .direction === 'left'}}class-going-left{{else}}class-going-right{{/if}}>
  3.     <div class-tabs>
  4.       <div class="left-tabs">
  5.         {{#each .tabs}}{{#unless .right}}{{>tab}}{{/unless}}{{/each}}
  6.       </div>
  7.       <div class="right-tabs">
  8.         {{#each .tabs}}{{#if .right}}{{>tab}}{{/if}}{{/each}}
  9.       </div>
  10.       <div class="selection-indicator" style-left="{{.selectedLeft}}px" {{#if .selectedRight !== undefined}}style-right="{{.selectedRight}}px"{{/if}} />
  11.       </div>
  12.   </div>
  13.   <div class-content-window
  14.    {{#if .transition === 'fade'}}
  15.      style-opacity="{{opacity}}"
  16.      class-trans-fade
  17.    {{elseif .transition === 'slide'}}
  18.      class-trans-slide
  19.    {{/if}}
  20.  >
  21.     <div class-contents style-left="{{.selectedContent * -100}}%">
  22.       {{#each .tabs}}{{>tab-content}}{{/each}}
  23.     </div>
  24.   </div>
  25. </div>
  26.  
  27. <template id="tab">
  28.   <div
  29.    class-tab
  30.    {{#unless .button}}class-selected="~/selected === @index"{{/unless}}
  31.  
  32.    {{#if .disabled}}class-disabled
  33.    {{elseif !.button}}on-click=['select', @index]{{/if}}
  34.    as-registered="@index"
  35.    {{#if .extraTab}}{{yield .extraTab}}{{/if}}
  36.  >
  37.     {{#if typeof .title === 'string'}}{{title}}{{elseif .title}}{{yield .title}}{{/if}}
  38.     {{#if .closable && !.button}}<div class-close on-click=['close', @index]>&times;</div>{{/if}}
  39.   </div>
  40. </template>
  41.  
  42. <template id="tab-content">
  43.   {{#if !.button}}
  44.     <div
  45.      class-tab
  46.      class-selected="~/selectedContent === @index"
  47.      {{#if .extra}}{{yield .extra}}{{/if}}
  48.    >
  49.       {{yield .template}}
  50.     </div>
  51.   {{else}}<div class-tab />
  52.   {{/if}}
  53. </template>
  54.  
  55. <script>
  56.   import Ractive from 'ractive';
  57.  
  58.   let resizer;
  59.   const instances = [];
  60.  
  61.   class Tabs extends Ractive {
  62.     constructor(opts) {
  63.       super(opts);
  64.     }
  65.  
  66.     updateIndicator() {
  67.       const node = this._tabs[this.get('selected')];
  68.  
  69.       if (node) {
  70.         const start = this.get('selectedLeft');
  71.         if (start === undefined) {
  72.           this.set({
  73.             selectedLeft: node.offsetLeft,
  74.             selectedRight: node.offsetParent.clientWidth - (node.offsetLeft + node.offsetWidth)
  75.           });
  76.         } else {
  77.           const max = node.offsetParent.clientWidth;
  78.           const left = node.offsetLeft, width = node.clientWidth, right = max - left - width;
  79.  
  80.           this.set({
  81.             direction: left < start ? 'left' : 'right',
  82.            selectedLeft: left,
  83.            selectedRight: right
  84.          });
  85.        }
  86.      } else {
  87.        this.set({
  88.          selectedLeft: 0,
  89.          selectedRight: this.find('.tabs').offsetWidth
  90.        });
  91.      }
  92.    }
  93.  }
  94.  
  95.  const tabAttrs = ['closable', 'disabled', 'title', 'right', 'button'];
  96.  
  97.  Ractive.extendWith(Tabs, {
  98.    template: $TEMPLATE,
  99.    cssId: 'tabs',
  100.    noCssTransform: true,
  101.    css: $CSS,
  102.    attributes: ['transition'],
  103.    data() {
  104.      return {
  105.        tabs: [],
  106.        rightTabs: [],
  107.        selected: 0,
  108.        selectedContent: 0,
  109.        opacity: 1
  110.      }
  111.    },
  112.    on: {
  113.      config() {
  114.        const tpl = this.partials.content;
  115.        if (tpl) {
  116.          const tabs = tpl.filter(n => n.e === 'tab').map(t => {
  117.             const tab = {
  118.               template: { t: t.f }
  119.             };
  120.             const extra = [];
  121.             const extraTab = [];
  122.  
  123.             t.m.forEach(a => {
  124.               if (a.t === 13 && ~tabAttrs.indexOf(a.n)) tab[a.n] = a.f === 0 ? true : typeof a.f === 'string' ? a.f : { t: a.f };
  125.               else if (a.t === 70) extraTab.push(a);
  126.               else extra.push(a);
  127.             });
  128.  
  129.             if (extra.length) tab.extra = { t: extra };
  130.             if (extraTab.length) tab.extraTab = { t: extraTab };
  131.  
  132.             return tab;
  133.           });
  134.  
  135.           tabs.unshift('tabs');
  136.           this.push.apply(this, tabs);
  137.  
  138.           if (!resizer && typeof window !== undefined) {
  139.            resizer = true;
  140.             window.addEventListener('resize', () => {
  141.               instances.forEach(i => i.updateIndicator());
  142.             });
  143.           }
  144.  
  145.           instances.push(this);
  146.           }
  147.       },
  148.       select(ctx, idx) {
  149.         const current = this.get('selected');
  150.         const prs = [];
  151.         const node = this.find('.contents');
  152.         const trans = this.get('transition');
  153.  
  154.         if (current !== idx) {
  155.           if (trans === 'fade') {
  156.             this.set({
  157.               opacity: 0,
  158.               selected: idx
  159.             });
  160.             this.updateIndicator();
  161.  
  162.             setTimeout(() => {
  163.               this.set({
  164.                 selectedContent: idx,
  165.                 opacity: 1
  166.               });
  167.             }, 300);
  168.           } else if (trans === 'slide') {
  169.             this.set('selected', idx);
  170.             this.set('selectedContent', idx);
  171.             this.updateIndicator();
  172.           } else {
  173.             this.set({
  174.               selected: idx,
  175.               selectedContent: idx
  176.             });
  177.             this.updateIndicator();
  178.           }
  179.         }
  180.       },
  181.       close(ctx, idx) {
  182.         const tab = this.getContext(this._tabs[idx]);
  183.         let ok = true;
  184.  
  185.         if (tab.element.events.find(e => e.events.find(e => e.name === 'close'))) {
  186.           ok = tab.raise('close');
  187.         }
  188.  
  189.         if (ok) this.splice('tabs', idx, 1);
  190.  
  191.         return false;
  192.       },
  193.       teardown() {
  194.         instances.splice(instances.indexOf(this), 1);
  195.       }
  196.     },
  197.     decorators: {
  198.       registered(node, idx) {
  199.         const me = this;
  200.  
  201.         if (!this._tabs) this._tabs = [];
  202.  
  203.         this._tabs[idx] = node;
  204.         this.updateIndicator();
  205.  
  206.         return {
  207.           teardown() {},
  208.           invalidate() {
  209.             me.updateIndicator();
  210.           },
  211.           update(idx) {
  212.             me._tabs[idx] = node;
  213.             setTimeout(() => me.updateIndicator());
  214.           }
  215.         };
  216.       }
  217.     }
  218.   });
  219.  
  220.   export default Tabs;
  221. </script>
  222.  
  223. <style>
  224.   .rtabs {
  225.     position: relative;
  226.   }
  227.  
  228.   .rtabs > .tab-window {
  229.     overflow-y: hidden;
  230.     overflow-x: auto;
  231.     box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
  232.       0 1px 5px 0 rgba(0, 0, 0, 0.12),
  233.       0 3px 1px -2px rgba(0, 0, 0, 0.2);
  234.   }
  235.  
  236.   .rtabs > .tab-window .tabs {
  237.     display: table;
  238.     position: relative;
  239.     min-width: 100%;
  240.     overflow-x: auto;
  241.     overflow-y: hidden;
  242.     white-space: nowrap;
  243.   }
  244.  
  245.   .rtabs > .tab-window .tab {
  246.     display: inline-block;
  247.     box-sizing: border-box;
  248.     padding: 0.5em 1em;
  249.     height: 2.5em;
  250.     cursor: pointer;
  251.     opacity: 0.7;
  252.     transition: opacity 0.2s ease-in-out;
  253.     user-select: none;
  254.   }
  255.   .rtabs > .tab-window .tab:hover {
  256.     opacity: 1;
  257.   }
  258.  
  259.   .rtabs > .tab-window .tab.selected {
  260.     opacity: 1;
  261.   }
  262.  
  263.   .rtabs > .tab-window .tab.disabled {
  264.     opacity: 0.4;
  265.   }
  266.  
  267.   .rtabs > .tab-window .right-tabs {
  268.     text-align: right;
  269.     display: table-cell;
  270.   }
  271.  
  272.   .rtabs > .tab-window .left-tabs {
  273.     text-align: left;
  274.     display: table-cell;
  275.   }
  276.  
  277.   .rtabs > .tab-window .tab > .close {
  278.     display: inline-block;
  279.     margin-right: -0.5em;
  280.     font-weight: 700;
  281.   }
  282.  
  283.   .rtabs > .tab-window .selection-indicator {
  284.     position: absolute;
  285.     bottom: 0;
  286.     height: 2px;
  287.     background-color: blue;
  288.   }
  289.   .rtabs > .tab-window.going-left .selection-indicator {
  290.     transition: left 0.2s ease-in-out, right 0.2s ease-in-out 0.1s;
  291.   }
  292.   .rtabs > .tab-window.going-right .selection-indicator {
  293.     transition: left 0.2s ease-in-out 0.1s, right 0.2s ease-in-out;
  294.   }
  295.  
  296.   .rtabs > .content-window {
  297.     width: 100%;
  298.     overflow: hidden;
  299.   }
  300.  
  301.   .rtabs > .content-window > .contents {
  302.     list-style: none;
  303.     padding: 0;
  304.     margin: 0;
  305.     position: relative;
  306.     white-space: nowrap;
  307.     left: 0;
  308.   }
  309.   .rtabs > .content-window.trans-slide > .contents {
  310.     transition: left 0.45s ease-in-out;
  311.   }
  312.   .rtabs > .content-window.trans-fade {
  313.     transition: opacity 0.3s ease;
  314.   }
  315.  
  316.   .rtabs > .content-window > .contents > .tab {
  317.     display: inline-block;
  318.     width: 100%;
  319.     vertical-align: top;
  320.     white-space: initial;
  321.     transition: opacity 0.1s ease-in-out;
  322.   }
  323. </style>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement