github.com/fanux/shipyard@v0.0.0-20161009071005-6515ce223235/controller/static/semantic/src/definitions/modules/shape.js (about)

     1  /*!
     2   * # Semantic UI - Shape
     3   * http://github.com/semantic-org/semantic-ui/
     4   *
     5   *
     6   * Copyright 2014 Contributors
     7   * Released under the MIT license
     8   * http://opensource.org/licenses/MIT
     9   *
    10   */
    11  
    12  ;(function ( $, window, document, undefined ) {
    13  
    14  "use strict";
    15  
    16  $.fn.shape = function(parameters) {
    17    var
    18      $allModules     = $(this),
    19      $body           = $('body'),
    20  
    21      time            = new Date().getTime(),
    22      performance     = [],
    23  
    24      query           = arguments[0],
    25      methodInvoked   = (typeof query == 'string'),
    26      queryArguments  = [].slice.call(arguments, 1),
    27  
    28      requestAnimationFrame = window.requestAnimationFrame
    29        || window.mozRequestAnimationFrame
    30        || window.webkitRequestAnimationFrame
    31        || window.msRequestAnimationFrame
    32        || function(callback) { setTimeout(callback, 0); },
    33  
    34      returnedValue
    35    ;
    36  
    37    $allModules
    38      .each(function() {
    39        var
    40          moduleSelector  = $allModules.selector || '',
    41          settings        = $.extend(true, {}, $.fn.shape.settings, parameters),
    42  
    43          // internal aliases
    44          namespace     = settings.namespace,
    45          selector      = settings.selector,
    46          error         = settings.error,
    47          className     = settings.className,
    48  
    49          // define namespaces for modules
    50          eventNamespace  = '.' + namespace,
    51          moduleNamespace = 'module-' + namespace,
    52  
    53          // selector cache
    54          $module       = $(this),
    55          $sides        = $module.find(selector.sides),
    56          $side         = $module.find(selector.side),
    57  
    58          // private variables
    59          nextIndex = false,
    60          $activeSide,
    61          $nextSide,
    62  
    63          // standard module
    64          element       = this,
    65          instance      = $module.data(moduleNamespace),
    66          module
    67        ;
    68  
    69        module = {
    70  
    71          initialize: function() {
    72            module.verbose('Initializing module for', element);
    73            module.set.defaultSide();
    74            module.instantiate();
    75          },
    76  
    77          instantiate: function() {
    78            module.verbose('Storing instance of module', module);
    79            instance = module;
    80            $module
    81              .data(moduleNamespace, instance)
    82            ;
    83          },
    84  
    85          destroy: function() {
    86            module.verbose('Destroying previous module for', element);
    87            $module
    88              .removeData(moduleNamespace)
    89              .off(eventNamespace)
    90            ;
    91          },
    92  
    93          refresh: function() {
    94            module.verbose('Refreshing selector cache for', element);
    95            $module = $(element);
    96            $sides  = $(this).find(selector.shape);
    97            $side   = $(this).find(selector.side);
    98          },
    99  
   100          repaint: function() {
   101            module.verbose('Forcing repaint event');
   102            var
   103              shape          = $sides.get(0) || document.createElement('div'),
   104              fakeAssignment = shape.offsetWidth
   105            ;
   106          },
   107  
   108          animate: function(propertyObject, callback) {
   109            module.verbose('Animating box with properties', propertyObject);
   110            callback = callback || function(event) {
   111              module.verbose('Executing animation callback');
   112              if(event !== undefined) {
   113                event.stopPropagation();
   114              }
   115              module.reset();
   116              module.set.active();
   117            };
   118            settings.beforeChange.call($nextSide.get());
   119            if(module.get.transitionEvent()) {
   120              module.verbose('Starting CSS animation');
   121              $module
   122                .addClass(className.animating)
   123              ;
   124              $sides
   125                .css(propertyObject)
   126                .one(module.get.transitionEvent(), callback)
   127              ;
   128              module.set.duration(settings.duration);
   129              requestAnimationFrame(function() {
   130                $module
   131                  .addClass(className.animating)
   132                ;
   133                $activeSide
   134                  .addClass(className.hidden)
   135                ;
   136              });
   137            }
   138            else {
   139              callback();
   140            }
   141          },
   142  
   143          queue: function(method) {
   144            module.debug('Queueing animation of', method);
   145            $sides
   146              .one(module.get.transitionEvent(), function() {
   147                module.debug('Executing queued animation');
   148                setTimeout(function(){
   149                  $module.shape(method);
   150                }, 0);
   151              })
   152            ;
   153          },
   154  
   155          reset: function() {
   156            module.verbose('Animating states reset');
   157            $module
   158              .removeClass(className.animating)
   159              .attr('style', '')
   160              .removeAttr('style')
   161            ;
   162            // removeAttr style does not consistently work in safari
   163            $sides
   164              .attr('style', '')
   165              .removeAttr('style')
   166            ;
   167            $side
   168              .attr('style', '')
   169              .removeAttr('style')
   170              .removeClass(className.hidden)
   171            ;
   172            $nextSide
   173              .removeClass(className.animating)
   174              .attr('style', '')
   175              .removeAttr('style')
   176            ;
   177          },
   178  
   179          is: {
   180            complete: function() {
   181              return ($side.filter('.' + className.active)[0] == $nextSide[0]);
   182            },
   183            animating: function() {
   184              return $module.hasClass(className.animating);
   185            }
   186          },
   187  
   188          set: {
   189  
   190            defaultSide: function() {
   191              $activeSide = $module.find('.' + settings.className.active);
   192              $nextSide   = ( $activeSide.next(selector.side).length > 0 )
   193                ? $activeSide.next(selector.side)
   194                : $module.find(selector.side).first()
   195              ;
   196              nextIndex = false;
   197              module.verbose('Active side set to', $activeSide);
   198              module.verbose('Next side set to', $nextSide);
   199            },
   200  
   201            duration: function(duration) {
   202              duration = duration || settings.duration;
   203              duration = (typeof duration == 'number')
   204                ? duration + 'ms'
   205                : duration
   206              ;
   207              module.verbose('Setting animation duration', duration);
   208              $sides.add($side)
   209                .css({
   210                  '-webkit-transition-duration': duration,
   211                  '-moz-transition-duration': duration,
   212                  '-ms-transition-duration': duration,
   213                  '-o-transition-duration': duration,
   214                  'transition-duration': duration
   215                })
   216              ;
   217            },
   218  
   219            stageSize: function() {
   220              var
   221                $clone      = $module.clone().addClass(className.loading),
   222                $activeSide = $clone.find('.' + settings.className.active),
   223                $nextSide   = (nextIndex)
   224                  ? $clone.find(selector.side).eq(nextIndex)
   225                  : ( $activeSide.next(selector.side).length > 0 )
   226                    ? $activeSide.next(selector.side)
   227                    : $clone.find(selector.side).first(),
   228                newSize = {}
   229              ;
   230              $activeSide.removeClass(className.active);
   231              $nextSide.addClass(className.active);
   232              $clone.insertAfter($module);
   233              newSize = {
   234                width  : $nextSide.outerWidth(),
   235                height : $nextSide.outerHeight()
   236              };
   237              $clone.remove();
   238              $module
   239                .css(newSize)
   240              ;
   241              module.verbose('Resizing stage to fit new content', newSize);
   242            },
   243  
   244            nextSide: function(selector) {
   245              nextIndex = selector;
   246              $nextSide = $side.filter(selector);
   247              nextIndex = $side.index($nextSide);
   248              if($nextSide.length === 0) {
   249                module.set.defaultSide();
   250                module.error(error.side);
   251              }
   252              module.verbose('Next side manually set to', $nextSide);
   253            },
   254  
   255            active: function() {
   256              module.verbose('Setting new side to active', $nextSide);
   257              $side
   258                .removeClass(className.active)
   259              ;
   260              $nextSide
   261                .addClass(className.active)
   262              ;
   263              settings.onChange.call($nextSide.get());
   264              module.set.defaultSide();
   265            }
   266          },
   267  
   268          flip: {
   269  
   270            up: function() {
   271              if(module.is.complete() && !module.is.animating() && !settings.allowRepeats) {
   272                module.debug('Side already visible', $nextSide);
   273                return;
   274              }
   275              if( !module.is.animating()) {
   276                module.debug('Flipping up', $nextSide);
   277                module.set.stageSize();
   278                module.stage.above();
   279                module.animate( module.get.transform.up() );
   280              }
   281              else {
   282                module.queue('flip up');
   283              }
   284            },
   285  
   286            down: function() {
   287              if(module.is.complete() && !module.is.animating() && !settings.allowRepeats) {
   288                module.debug('Side already visible', $nextSide);
   289                return;
   290              }
   291              if( !module.is.animating()) {
   292                module.debug('Flipping down', $nextSide);
   293                module.set.stageSize();
   294                module.stage.below();
   295                module.animate( module.get.transform.down() );
   296              }
   297              else {
   298                module.queue('flip down');
   299              }
   300            },
   301  
   302            left: function() {
   303              if(module.is.complete() && !module.is.animating() && !settings.allowRepeats) {
   304                module.debug('Side already visible', $nextSide);
   305                return;
   306              }
   307              if( !module.is.animating()) {
   308                module.debug('Flipping left', $nextSide);
   309                module.set.stageSize();
   310                module.stage.left();
   311                module.animate(module.get.transform.left() );
   312              }
   313              else {
   314                module.queue('flip left');
   315              }
   316            },
   317  
   318            right: function() {
   319              if(module.is.complete() && !module.is.animating() && !settings.allowRepeats) {
   320                module.debug('Side already visible', $nextSide);
   321                return;
   322              }
   323              if( !module.is.animating()) {
   324                module.debug('Flipping right', $nextSide);
   325                module.set.stageSize();
   326                module.stage.right();
   327                module.animate(module.get.transform.right() );
   328              }
   329              else {
   330                module.queue('flip right');
   331              }
   332            },
   333  
   334            over: function() {
   335              if(module.is.complete() && !module.is.animating() && !settings.allowRepeats) {
   336                module.debug('Side already visible', $nextSide);
   337                return;
   338              }
   339              if( !module.is.animating()) {
   340                module.debug('Flipping over', $nextSide);
   341                module.set.stageSize();
   342                module.stage.behind();
   343                module.animate(module.get.transform.over() );
   344              }
   345              else {
   346                module.queue('flip over');
   347              }
   348            },
   349  
   350            back: function() {
   351              if(module.is.complete() && !module.is.animating() && !settings.allowRepeats) {
   352                module.debug('Side already visible', $nextSide);
   353                return;
   354              }
   355              if( !module.is.animating()) {
   356                module.debug('Flipping back', $nextSide);
   357                module.set.stageSize();
   358                module.stage.behind();
   359                module.animate(module.get.transform.back() );
   360              }
   361              else {
   362                module.queue('flip back');
   363              }
   364            }
   365  
   366          },
   367  
   368          get: {
   369  
   370            transform: {
   371              up: function() {
   372                var
   373                  translate = {
   374                    y: -(($activeSide.outerHeight() - $nextSide.outerHeight()) / 2),
   375                    z: -($activeSide.outerHeight() / 2)
   376                  }
   377                ;
   378                return {
   379                  transform: 'translateY(' + translate.y + 'px) translateZ('+ translate.z + 'px) rotateX(-90deg)'
   380                };
   381              },
   382  
   383              down: function() {
   384                var
   385                  translate = {
   386                    y: -(($activeSide.outerHeight() - $nextSide.outerHeight()) / 2),
   387                    z: -($activeSide.outerHeight() / 2)
   388                  }
   389                ;
   390                return {
   391                  transform: 'translateY(' + translate.y + 'px) translateZ('+ translate.z + 'px) rotateX(90deg)'
   392                };
   393              },
   394  
   395              left: function() {
   396                var
   397                  translate = {
   398                    x : -(($activeSide.outerWidth() - $nextSide.outerWidth()) / 2),
   399                    z : -($activeSide.outerWidth() / 2)
   400                  }
   401                ;
   402                return {
   403                  transform: 'translateX(' + translate.x + 'px) translateZ(' + translate.z + 'px) rotateY(90deg)'
   404                };
   405              },
   406  
   407              right: function() {
   408                var
   409                  translate = {
   410                    x : -(($activeSide.outerWidth() - $nextSide.outerWidth()) / 2),
   411                    z : -($activeSide.outerWidth() / 2)
   412                  }
   413                ;
   414                return {
   415                  transform: 'translateX(' + translate.x + 'px) translateZ(' + translate.z + 'px) rotateY(-90deg)'
   416                };
   417              },
   418  
   419              over: function() {
   420                var
   421                  translate = {
   422                    x : -(($activeSide.outerWidth() - $nextSide.outerWidth()) / 2)
   423                  }
   424                ;
   425                return {
   426                  transform: 'translateX(' + translate.x + 'px) rotateY(180deg)'
   427                };
   428              },
   429  
   430              back: function() {
   431                var
   432                  translate = {
   433                    x : -(($activeSide.outerWidth() - $nextSide.outerWidth()) / 2)
   434                  }
   435                ;
   436                return {
   437                  transform: 'translateX(' + translate.x + 'px) rotateY(-180deg)'
   438                };
   439              }
   440            },
   441  
   442            transitionEvent: function() {
   443              var
   444                element     = document.createElement('element'),
   445                transitions = {
   446                  'transition'       :'transitionend',
   447                  'OTransition'      :'oTransitionEnd',
   448                  'MozTransition'    :'transitionend',
   449                  'WebkitTransition' :'webkitTransitionEnd'
   450                },
   451                transition
   452              ;
   453              for(transition in transitions){
   454                if( element.style[transition] !== undefined ){
   455                  return transitions[transition];
   456                }
   457              }
   458            },
   459  
   460            nextSide: function() {
   461              return ( $activeSide.next(selector.side).length > 0 )
   462                ? $activeSide.next(selector.side)
   463                : $module.find(selector.side).first()
   464              ;
   465            }
   466  
   467          },
   468  
   469          stage: {
   470  
   471            above: function() {
   472              var
   473                box = {
   474                  origin : (($activeSide.outerHeight() - $nextSide.outerHeight()) / 2),
   475                  depth  : {
   476                    active : ($nextSide.outerHeight() / 2),
   477                    next   : ($activeSide.outerHeight() / 2)
   478                  }
   479                }
   480              ;
   481              module.verbose('Setting the initial animation position as above', $nextSide, box);
   482              $activeSide
   483                .css({
   484                  'transform' : 'rotateY(0deg) translateZ(' + box.depth.active + 'px)'
   485                })
   486              ;
   487              $nextSide
   488                .addClass(className.animating)
   489                .css({
   490                  'display'   : 'block',
   491                  'top'       : box.origin + 'px',
   492                  'transform' : 'rotateX(90deg) translateZ(' + box.depth.next + 'px)'
   493                })
   494              ;
   495            },
   496  
   497            below: function() {
   498              var
   499                box = {
   500                  origin : (($activeSide.outerHeight() - $nextSide.outerHeight()) / 2),
   501                  depth  : {
   502                    active : ($nextSide.outerHeight() / 2),
   503                    next   : ($activeSide.outerHeight() / 2)
   504                  }
   505                }
   506              ;
   507              module.verbose('Setting the initial animation position as below', $nextSide, box);
   508              $activeSide
   509                .css({
   510                  'transform' : 'rotateY(0deg) translateZ(' + box.depth.active + 'px)'
   511                })
   512              ;
   513              $nextSide
   514                .addClass(className.animating)
   515                .css({
   516                  'display'   : 'block',
   517                  'top'       : box.origin + 'px',
   518                  'transform' : 'rotateX(-90deg) translateZ(' + box.depth.next + 'px)'
   519                })
   520              ;
   521            },
   522  
   523            left: function() {
   524              var
   525                box = {
   526                  origin : ( ( $activeSide.outerWidth() - $nextSide.outerWidth() ) / 2),
   527                  depth  : {
   528                    active : ($nextSide.outerWidth() / 2),
   529                    next   : ($activeSide.outerWidth() / 2)
   530                  }
   531                }
   532              ;
   533              module.verbose('Setting the initial animation position as left', $nextSide, box);
   534              $activeSide
   535                .css({
   536                  'transform' : 'rotateY(0deg) translateZ(' + box.depth.active + 'px)'
   537                })
   538              ;
   539              $nextSide
   540                .addClass(className.animating)
   541                .css({
   542                  'display'   : 'block',
   543                  'left'      : box.origin + 'px',
   544                  'transform' : 'rotateY(-90deg) translateZ(' + box.depth.next + 'px)'
   545                })
   546              ;
   547            },
   548  
   549            right: function() {
   550              var
   551                box = {
   552                  origin : ( ( $activeSide.outerWidth() - $nextSide.outerWidth() ) / 2),
   553                  depth  : {
   554                    active : ($nextSide.outerWidth() / 2),
   555                    next   : ($activeSide.outerWidth() / 2)
   556                  }
   557                }
   558              ;
   559              module.verbose('Setting the initial animation position as left', $nextSide, box);
   560              $activeSide
   561                .css({
   562                  'transform' : 'rotateY(0deg) translateZ(' + box.depth.active + 'px)'
   563                })
   564              ;
   565              $nextSide
   566                .addClass(className.animating)
   567                .css({
   568                  'display'   : 'block',
   569                  'left'      : box.origin + 'px',
   570                  'transform' : 'rotateY(90deg) translateZ(' + box.depth.next + 'px)'
   571                })
   572              ;
   573            },
   574  
   575            behind: function() {
   576              var
   577                box = {
   578                  origin : ( ( $activeSide.outerWidth() - $nextSide.outerWidth() ) / 2),
   579                  depth  : {
   580                    active : ($nextSide.outerWidth() / 2),
   581                    next   : ($activeSide.outerWidth() / 2)
   582                  }
   583                }
   584              ;
   585              module.verbose('Setting the initial animation position as behind', $nextSide, box);
   586              $activeSide
   587                .css({
   588                  'transform' : 'rotateY(0deg)'
   589                })
   590              ;
   591              $nextSide
   592                .addClass(className.animating)
   593                .css({
   594                  'display'   : 'block',
   595                  'left'      : box.origin + 'px',
   596                  'transform' : 'rotateY(-180deg)'
   597                })
   598              ;
   599            }
   600          },
   601          setting: function(name, value) {
   602            module.debug('Changing setting', name, value);
   603            if( $.isPlainObject(name) ) {
   604              $.extend(true, settings, name);
   605            }
   606            else if(value !== undefined) {
   607              settings[name] = value;
   608            }
   609            else {
   610              return settings[name];
   611            }
   612          },
   613          internal: function(name, value) {
   614            if( $.isPlainObject(name) ) {
   615              $.extend(true, module, name);
   616            }
   617            else if(value !== undefined) {
   618              module[name] = value;
   619            }
   620            else {
   621              return module[name];
   622            }
   623          },
   624          debug: function() {
   625            if(settings.debug) {
   626              if(settings.performance) {
   627                module.performance.log(arguments);
   628              }
   629              else {
   630                module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
   631                module.debug.apply(console, arguments);
   632              }
   633            }
   634          },
   635          verbose: function() {
   636            if(settings.verbose && settings.debug) {
   637              if(settings.performance) {
   638                module.performance.log(arguments);
   639              }
   640              else {
   641                module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
   642                module.verbose.apply(console, arguments);
   643              }
   644            }
   645          },
   646          error: function() {
   647            module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
   648            module.error.apply(console, arguments);
   649          },
   650          performance: {
   651            log: function(message) {
   652              var
   653                currentTime,
   654                executionTime,
   655                previousTime
   656              ;
   657              if(settings.performance) {
   658                currentTime   = new Date().getTime();
   659                previousTime  = time || currentTime;
   660                executionTime = currentTime - previousTime;
   661                time          = currentTime;
   662                performance.push({
   663                  'Name'           : message[0],
   664                  'Arguments'      : [].slice.call(message, 1) || '',
   665                  'Element'        : element,
   666                  'Execution Time' : executionTime
   667                });
   668              }
   669              clearTimeout(module.performance.timer);
   670              module.performance.timer = setTimeout(module.performance.display, 100);
   671            },
   672            display: function() {
   673              var
   674                title = settings.name + ':',
   675                totalTime = 0
   676              ;
   677              time = false;
   678              clearTimeout(module.performance.timer);
   679              $.each(performance, function(index, data) {
   680                totalTime += data['Execution Time'];
   681              });
   682              title += ' ' + totalTime + 'ms';
   683              if(moduleSelector) {
   684                title += ' \'' + moduleSelector + '\'';
   685              }
   686              if($allModules.length > 1) {
   687                title += ' ' + '(' + $allModules.length + ')';
   688              }
   689              if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
   690                console.groupCollapsed(title);
   691                if(console.table) {
   692                  console.table(performance);
   693                }
   694                else {
   695                  $.each(performance, function(index, data) {
   696                    console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
   697                  });
   698                }
   699                console.groupEnd();
   700              }
   701              performance = [];
   702            }
   703          },
   704          invoke: function(query, passedArguments, context) {
   705            var
   706              object = instance,
   707              maxDepth,
   708              found,
   709              response
   710            ;
   711            passedArguments = passedArguments || queryArguments;
   712            context         = element         || context;
   713            if(typeof query == 'string' && object !== undefined) {
   714              query    = query.split(/[\. ]/);
   715              maxDepth = query.length - 1;
   716              $.each(query, function(depth, value) {
   717                var camelCaseValue = (depth != maxDepth)
   718                  ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
   719                  : query
   720                ;
   721                if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
   722                  object = object[camelCaseValue];
   723                }
   724                else if( object[camelCaseValue] !== undefined ) {
   725                  found = object[camelCaseValue];
   726                  return false;
   727                }
   728                else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
   729                  object = object[value];
   730                }
   731                else if( object[value] !== undefined ) {
   732                  found = object[value];
   733                  return false;
   734                }
   735                else {
   736                  return false;
   737                }
   738              });
   739            }
   740            if ( $.isFunction( found ) ) {
   741              response = found.apply(context, passedArguments);
   742            }
   743            else if(found !== undefined) {
   744              response = found;
   745            }
   746            if($.isArray(returnedValue)) {
   747              returnedValue.push(response);
   748            }
   749            else if(returnedValue !== undefined) {
   750              returnedValue = [returnedValue, response];
   751            }
   752            else if(response !== undefined) {
   753              returnedValue = response;
   754            }
   755            return found;
   756          }
   757        };
   758  
   759        if(methodInvoked) {
   760          if(instance === undefined) {
   761            module.initialize();
   762          }
   763          module.invoke(query);
   764        }
   765        else {
   766          if(instance !== undefined) {
   767            instance.invoke('destroy');
   768          }
   769          module.initialize();
   770        }
   771      })
   772    ;
   773  
   774    return (returnedValue !== undefined)
   775      ? returnedValue
   776      : this
   777    ;
   778  };
   779  
   780  $.fn.shape.settings = {
   781  
   782    // module info
   783    name : 'Shape',
   784  
   785    // debug content outputted to console
   786    debug      : false,
   787  
   788    // verbose debug output
   789    verbose    : true,
   790  
   791    // performance data output
   792    performance: true,
   793  
   794    // event namespace
   795    namespace  : 'shape',
   796  
   797    // callback occurs on side change
   798    beforeChange : function() {},
   799    onChange     : function() {},
   800  
   801    // allow animation to same side
   802    allowRepeats: false,
   803  
   804    // animation duration
   805    duration   : 700,
   806  
   807    // possible errors
   808    error: {
   809      side   : 'You tried to switch to a side that does not exist.',
   810      method : 'The method you called is not defined'
   811    },
   812  
   813    // classnames used
   814    className   : {
   815      animating : 'animating',
   816      hidden    : 'hidden',
   817      loading   : 'loading',
   818      active    : 'active'
   819    },
   820  
   821    // selectors used
   822    selector    : {
   823      sides : '.sides',
   824      side  : '.side'
   825    }
   826  
   827  };
   828  
   829  
   830  })( jQuery, window , document );