Code Duplication    Length = 698-698 lines in 2 locations

public/lib/semantic/semantic.js 1 location

@@ 20874-21571 (lines=698) @@
20871
 *
20872
 */
20873
20874
;(function ($, window, document, undefined) {
20875
20876
"use strict";
20877
20878
window = (typeof window != 'undefined' && window.Math == Math)
20879
  ? window
20880
  : (typeof self != 'undefined' && self.Math == Math)
20881
    ? self
20882
    : Function('return this')()
20883
;
20884
20885
$.fn.state = function(parameters) {
20886
  var
20887
    $allModules     = $(this),
20888
20889
    moduleSelector  = $allModules.selector || '',
20890
20891
    hasTouch        = ('ontouchstart' in document.documentElement),
20892
    time            = new Date().getTime(),
20893
    performance     = [],
20894
20895
    query           = arguments[0],
20896
    methodInvoked   = (typeof query == 'string'),
20897
    queryArguments  = [].slice.call(arguments, 1),
20898
20899
    returnedValue
20900
  ;
20901
  $allModules
20902
    .each(function() {
20903
      var
20904
        settings          = ( $.isPlainObject(parameters) )
20905
          ? $.extend(true, {}, $.fn.state.settings, parameters)
20906
          : $.extend({}, $.fn.state.settings),
20907
20908
        error           = settings.error,
20909
        metadata        = settings.metadata,
20910
        className       = settings.className,
20911
        namespace       = settings.namespace,
20912
        states          = settings.states,
20913
        text            = settings.text,
20914
20915
        eventNamespace  = '.' + namespace,
20916
        moduleNamespace = namespace + '-module',
20917
20918
        $module         = $(this),
20919
20920
        element         = this,
20921
        instance        = $module.data(moduleNamespace),
20922
20923
        module
20924
      ;
20925
      module = {
20926
20927
        initialize: function() {
20928
          module.verbose('Initializing module');
20929
20930
          // allow module to guess desired state based on element
20931
          if(settings.automatic) {
20932
            module.add.defaults();
20933
          }
20934
20935
          // bind events with delegated events
20936
          if(settings.context && moduleSelector !== '') {
20937
            $(settings.context)
20938
              .on(moduleSelector, 'mouseenter' + eventNamespace, module.change.text)
20939
              .on(moduleSelector, 'mouseleave' + eventNamespace, module.reset.text)
20940
              .on(moduleSelector, 'click'      + eventNamespace, module.toggle.state)
20941
            ;
20942
          }
20943
          else {
20944
            $module
20945
              .on('mouseenter' + eventNamespace, module.change.text)
20946
              .on('mouseleave' + eventNamespace, module.reset.text)
20947
              .on('click'      + eventNamespace, module.toggle.state)
20948
            ;
20949
          }
20950
          module.instantiate();
20951
        },
20952
20953
        instantiate: function() {
20954
          module.verbose('Storing instance of module', module);
20955
          instance = module;
20956
          $module
20957
            .data(moduleNamespace, module)
20958
          ;
20959
        },
20960
20961
        destroy: function() {
20962
          module.verbose('Destroying previous module', instance);
20963
          $module
20964
            .off(eventNamespace)
20965
            .removeData(moduleNamespace)
20966
          ;
20967
        },
20968
20969
        refresh: function() {
20970
          module.verbose('Refreshing selector cache');
20971
          $module = $(element);
20972
        },
20973
20974
        add: {
20975
          defaults: function() {
20976
            var
20977
              userStates = parameters && $.isPlainObject(parameters.states)
20978
                ? parameters.states
20979
                : {}
20980
            ;
20981
            $.each(settings.defaults, function(type, typeStates) {
20982
              if( module.is[type] !== undefined && module.is[type]() ) {
20983
                module.verbose('Adding default states', type, element);
20984
                $.extend(settings.states, typeStates, userStates);
20985
              }
20986
            });
20987
          }
20988
        },
20989
20990
        is: {
20991
20992
          active: function() {
20993
            return $module.hasClass(className.active);
20994
          },
20995
          loading: function() {
20996
            return $module.hasClass(className.loading);
20997
          },
20998
          inactive: function() {
20999
            return !( $module.hasClass(className.active) );
21000
          },
21001
          state: function(state) {
21002
            if(className[state] === undefined) {
21003
              return false;
21004
            }
21005
            return $module.hasClass( className[state] );
21006
          },
21007
21008
          enabled: function() {
21009
            return !( $module.is(settings.filter.active) );
21010
          },
21011
          disabled: function() {
21012
            return ( $module.is(settings.filter.active) );
21013
          },
21014
          textEnabled: function() {
21015
            return !( $module.is(settings.filter.text) );
21016
          },
21017
21018
          // definitions for automatic type detection
21019
          button: function() {
21020
            return $module.is('.button:not(a, .submit)');
21021
          },
21022
          input: function() {
21023
            return $module.is('input');
21024
          },
21025
          progress: function() {
21026
            return $module.is('.ui.progress');
21027
          }
21028
        },
21029
21030
        allow: function(state) {
21031
          module.debug('Now allowing state', state);
21032
          states[state] = true;
21033
        },
21034
        disallow: function(state) {
21035
          module.debug('No longer allowing', state);
21036
          states[state] = false;
21037
        },
21038
21039
        allows: function(state) {
21040
          return states[state] || false;
21041
        },
21042
21043
        enable: function() {
21044
          $module.removeClass(className.disabled);
21045
        },
21046
21047
        disable: function() {
21048
          $module.addClass(className.disabled);
21049
        },
21050
21051
        setState: function(state) {
21052
          if(module.allows(state)) {
21053
            $module.addClass( className[state] );
21054
          }
21055
        },
21056
21057
        removeState: function(state) {
21058
          if(module.allows(state)) {
21059
            $module.removeClass( className[state] );
21060
          }
21061
        },
21062
21063
        toggle: {
21064
          state: function() {
21065
            var
21066
              apiRequest,
21067
              requestCancelled
21068
            ;
21069
            if( module.allows('active') && module.is.enabled() ) {
21070
              module.refresh();
21071
              if($.fn.api !== undefined) {
21072
                apiRequest       = $module.api('get request');
21073
                requestCancelled = $module.api('was cancelled');
21074
                if( requestCancelled ) {
21075
                  module.debug('API Request cancelled by beforesend');
21076
                  settings.activateTest   = function(){ return false; };
21077
                  settings.deactivateTest = function(){ return false; };
21078
                }
21079
                else if(apiRequest) {
21080
                  module.listenTo(apiRequest);
21081
                  return;
21082
                }
21083
              }
21084
              module.change.state();
21085
            }
21086
          }
21087
        },
21088
21089
        listenTo: function(apiRequest) {
21090
          module.debug('API request detected, waiting for state signal', apiRequest);
21091
          if(apiRequest) {
21092
            if(text.loading) {
21093
              module.update.text(text.loading);
21094
            }
21095
            $.when(apiRequest)
21096
              .then(function() {
21097
                if(apiRequest.state() == 'resolved') {
21098
                  module.debug('API request succeeded');
21099
                  settings.activateTest   = function(){ return true; };
21100
                  settings.deactivateTest = function(){ return true; };
21101
                }
21102
                else {
21103
                  module.debug('API request failed');
21104
                  settings.activateTest   = function(){ return false; };
21105
                  settings.deactivateTest = function(){ return false; };
21106
                }
21107
                module.change.state();
21108
              })
21109
            ;
21110
          }
21111
        },
21112
21113
        // checks whether active/inactive state can be given
21114
        change: {
21115
21116
          state: function() {
21117
            module.debug('Determining state change direction');
21118
            // inactive to active change
21119
            if( module.is.inactive() ) {
21120
              module.activate();
21121
            }
21122
            else {
21123
              module.deactivate();
21124
            }
21125
            if(settings.sync) {
21126
              module.sync();
21127
            }
21128
            settings.onChange.call(element);
21129
          },
21130
21131
          text: function() {
21132
            if( module.is.textEnabled() ) {
21133
              if(module.is.disabled() ) {
21134
                module.verbose('Changing text to disabled text', text.hover);
21135
                module.update.text(text.disabled);
21136
              }
21137
              else if( module.is.active() ) {
21138
                if(text.hover) {
21139
                  module.verbose('Changing text to hover text', text.hover);
21140
                  module.update.text(text.hover);
21141
                }
21142
                else if(text.deactivate) {
21143
                  module.verbose('Changing text to deactivating text', text.deactivate);
21144
                  module.update.text(text.deactivate);
21145
                }
21146
              }
21147
              else {
21148
                if(text.hover) {
21149
                  module.verbose('Changing text to hover text', text.hover);
21150
                  module.update.text(text.hover);
21151
                }
21152
                else if(text.activate){
21153
                  module.verbose('Changing text to activating text', text.activate);
21154
                  module.update.text(text.activate);
21155
                }
21156
              }
21157
            }
21158
          }
21159
21160
        },
21161
21162
        activate: function() {
21163
          if( settings.activateTest.call(element) ) {
21164
            module.debug('Setting state to active');
21165
            $module
21166
              .addClass(className.active)
21167
            ;
21168
            module.update.text(text.active);
21169
            settings.onActivate.call(element);
21170
          }
21171
        },
21172
21173
        deactivate: function() {
21174
          if( settings.deactivateTest.call(element) ) {
21175
            module.debug('Setting state to inactive');
21176
            $module
21177
              .removeClass(className.active)
21178
            ;
21179
            module.update.text(text.inactive);
21180
            settings.onDeactivate.call(element);
21181
          }
21182
        },
21183
21184
        sync: function() {
21185
          module.verbose('Syncing other buttons to current state');
21186
          if( module.is.active() ) {
21187
            $allModules
21188
              .not($module)
21189
                .state('activate');
21190
          }
21191
          else {
21192
            $allModules
21193
              .not($module)
21194
                .state('deactivate')
21195
            ;
21196
          }
21197
        },
21198
21199
        get: {
21200
          text: function() {
21201
            return (settings.selector.text)
21202
              ? $module.find(settings.selector.text).text()
21203
              : $module.html()
21204
            ;
21205
          },
21206
          textFor: function(state) {
21207
            return text[state] || false;
21208
          }
21209
        },
21210
21211
        flash: {
21212
          text: function(text, duration, callback) {
21213
            var
21214
              previousText = module.get.text()
21215
            ;
21216
            module.debug('Flashing text message', text, duration);
21217
            text     = text     || settings.text.flash;
21218
            duration = duration || settings.flashDuration;
21219
            callback = callback || function() {};
21220
            module.update.text(text);
21221
            setTimeout(function(){
21222
              module.update.text(previousText);
21223
              callback.call(element);
21224
            }, duration);
21225
          }
21226
        },
21227
21228
        reset: {
21229
          // on mouseout sets text to previous value
21230
          text: function() {
21231
            var
21232
              activeText   = text.active   || $module.data(metadata.storedText),
21233
              inactiveText = text.inactive || $module.data(metadata.storedText)
21234
            ;
21235
            if( module.is.textEnabled() ) {
21236
              if( module.is.active() && activeText) {
21237
                module.verbose('Resetting active text', activeText);
21238
                module.update.text(activeText);
21239
              }
21240
              else if(inactiveText) {
21241
                module.verbose('Resetting inactive text', activeText);
21242
                module.update.text(inactiveText);
21243
              }
21244
            }
21245
          }
21246
        },
21247
21248
        update: {
21249
          text: function(text) {
21250
            var
21251
              currentText = module.get.text()
21252
            ;
21253
            if(text && text !== currentText) {
21254
              module.debug('Updating text', text);
21255
              if(settings.selector.text) {
21256
                $module
21257
                  .data(metadata.storedText, text)
21258
                  .find(settings.selector.text)
21259
                    .text(text)
21260
                ;
21261
              }
21262
              else {
21263
                $module
21264
                  .data(metadata.storedText, text)
21265
                  .html(text)
21266
                ;
21267
              }
21268
            }
21269
            else {
21270
              module.debug('Text is already set, ignoring update', text);
21271
            }
21272
          }
21273
        },
21274
21275
        setting: function(name, value) {
21276
          module.debug('Changing setting', name, value);
21277
          if( $.isPlainObject(name) ) {
21278
            $.extend(true, settings, name);
21279
          }
21280
          else if(value !== undefined) {
21281
            if($.isPlainObject(settings[name])) {
21282
              $.extend(true, settings[name], value);
21283
            }
21284
            else {
21285
              settings[name] = value;
21286
            }
21287
          }
21288
          else {
21289
            return settings[name];
21290
          }
21291
        },
21292
        internal: function(name, value) {
21293
          if( $.isPlainObject(name) ) {
21294
            $.extend(true, module, name);
21295
          }
21296
          else if(value !== undefined) {
21297
            module[name] = value;
21298
          }
21299
          else {
21300
            return module[name];
21301
          }
21302
        },
21303
        debug: function() {
21304
          if(!settings.silent && settings.debug) {
21305
            if(settings.performance) {
21306
              module.performance.log(arguments);
21307
            }
21308
            else {
21309
              module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
21310
              module.debug.apply(console, arguments);
21311
            }
21312
          }
21313
        },
21314
        verbose: function() {
21315
          if(!settings.silent && settings.verbose && settings.debug) {
21316
            if(settings.performance) {
21317
              module.performance.log(arguments);
21318
            }
21319
            else {
21320
              module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
21321
              module.verbose.apply(console, arguments);
21322
            }
21323
          }
21324
        },
21325
        error: function() {
21326
          if(!settings.silent) {
21327
            module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
21328
            module.error.apply(console, arguments);
21329
          }
21330
        },
21331
        performance: {
21332
          log: function(message) {
21333
            var
21334
              currentTime,
21335
              executionTime,
21336
              previousTime
21337
            ;
21338
            if(settings.performance) {
21339
              currentTime   = new Date().getTime();
21340
              previousTime  = time || currentTime;
21341
              executionTime = currentTime - previousTime;
21342
              time          = currentTime;
21343
              performance.push({
21344
                'Name'           : message[0],
21345
                'Arguments'      : [].slice.call(message, 1) || '',
21346
                'Element'        : element,
21347
                'Execution Time' : executionTime
21348
              });
21349
            }
21350
            clearTimeout(module.performance.timer);
21351
            module.performance.timer = setTimeout(module.performance.display, 500);
21352
          },
21353
          display: function() {
21354
            var
21355
              title = settings.name + ':',
21356
              totalTime = 0
21357
            ;
21358
            time = false;
21359
            clearTimeout(module.performance.timer);
21360
            $.each(performance, function(index, data) {
21361
              totalTime += data['Execution Time'];
21362
            });
21363
            title += ' ' + totalTime + 'ms';
21364
            if(moduleSelector) {
21365
              title += ' \'' + moduleSelector + '\'';
21366
            }
21367
            if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
21368
              console.groupCollapsed(title);
21369
              if(console.table) {
21370
                console.table(performance);
21371
              }
21372
              else {
21373
                $.each(performance, function(index, data) {
21374
                  console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
21375
                });
21376
              }
21377
              console.groupEnd();
21378
            }
21379
            performance = [];
21380
          }
21381
        },
21382
        invoke: function(query, passedArguments, context) {
21383
          var
21384
            object = instance,
21385
            maxDepth,
21386
            found,
21387
            response
21388
          ;
21389
          passedArguments = passedArguments || queryArguments;
21390
          context         = element         || context;
21391
          if(typeof query == 'string' && object !== undefined) {
21392
            query    = query.split(/[\. ]/);
21393
            maxDepth = query.length - 1;
21394
            $.each(query, function(depth, value) {
21395
              var camelCaseValue = (depth != maxDepth)
21396
                ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
21397
                : query
21398
              ;
21399
              if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
21400
                object = object[camelCaseValue];
21401
              }
21402
              else if( object[camelCaseValue] !== undefined ) {
21403
                found = object[camelCaseValue];
21404
                return false;
21405
              }
21406
              else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
21407
                object = object[value];
21408
              }
21409
              else if( object[value] !== undefined ) {
21410
                found = object[value];
21411
                return false;
21412
              }
21413
              else {
21414
                module.error(error.method, query);
21415
                return false;
21416
              }
21417
            });
21418
          }
21419
          if ( $.isFunction( found ) ) {
21420
            response = found.apply(context, passedArguments);
21421
          }
21422
          else if(found !== undefined) {
21423
            response = found;
21424
          }
21425
          if($.isArray(returnedValue)) {
21426
            returnedValue.push(response);
21427
          }
21428
          else if(returnedValue !== undefined) {
21429
            returnedValue = [returnedValue, response];
21430
          }
21431
          else if(response !== undefined) {
21432
            returnedValue = response;
21433
          }
21434
          return found;
21435
        }
21436
      };
21437
21438
      if(methodInvoked) {
21439
        if(instance === undefined) {
21440
          module.initialize();
21441
        }
21442
        module.invoke(query);
21443
      }
21444
      else {
21445
        if(instance !== undefined) {
21446
          instance.invoke('destroy');
21447
        }
21448
        module.initialize();
21449
      }
21450
    })
21451
  ;
21452
21453
  return (returnedValue !== undefined)
21454
    ? returnedValue
21455
    : this
21456
  ;
21457
};
21458
21459
$.fn.state.settings = {
21460
21461
  // module info
21462
  name           : 'State',
21463
21464
  // debug output
21465
  debug          : false,
21466
21467
  // verbose debug output
21468
  verbose        : false,
21469
21470
  // namespace for events
21471
  namespace      : 'state',
21472
21473
  // debug data includes performance
21474
  performance    : true,
21475
21476
  // callback occurs on state change
21477
  onActivate     : function() {},
21478
  onDeactivate   : function() {},
21479
  onChange       : function() {},
21480
21481
  // state test functions
21482
  activateTest   : function() { return true; },
21483
  deactivateTest : function() { return true; },
21484
21485
  // whether to automatically map default states
21486
  automatic      : true,
21487
21488
  // activate / deactivate changes all elements instantiated at same time
21489
  sync           : false,
21490
21491
  // default flash text duration, used for temporarily changing text of an element
21492
  flashDuration  : 1000,
21493
21494
  // selector filter
21495
  filter     : {
21496
    text   : '.loading, .disabled',
21497
    active : '.disabled'
21498
  },
21499
21500
  context    : false,
21501
21502
  // error
21503
  error: {
21504
    beforeSend : 'The before send function has cancelled state change',
21505
    method     : 'The method you called is not defined.'
21506
  },
21507
21508
  // metadata
21509
  metadata: {
21510
    promise    : 'promise',
21511
    storedText : 'stored-text'
21512
  },
21513
21514
  // change class on state
21515
  className: {
21516
    active   : 'active',
21517
    disabled : 'disabled',
21518
    error    : 'error',
21519
    loading  : 'loading',
21520
    success  : 'success',
21521
    warning  : 'warning'
21522
  },
21523
21524
  selector: {
21525
    // selector for text node
21526
    text: false
21527
  },
21528
21529
  defaults : {
21530
    input: {
21531
      disabled : true,
21532
      loading  : true,
21533
      active   : true
21534
    },
21535
    button: {
21536
      disabled : true,
21537
      loading  : true,
21538
      active   : true,
21539
    },
21540
    progress: {
21541
      active   : true,
21542
      success  : true,
21543
      warning  : true,
21544
      error    : true
21545
    }
21546
  },
21547
21548
  states     : {
21549
    active   : true,
21550
    disabled : true,
21551
    error    : true,
21552
    loading  : true,
21553
    success  : true,
21554
    warning  : true
21555
  },
21556
21557
  text     : {
21558
    disabled   : false,
21559
    flash      : false,
21560
    hover      : false,
21561
    active     : false,
21562
    inactive   : false,
21563
    activate   : false,
21564
    deactivate : false
21565
  }
21566
21567
};
21568
21569
21570
21571
})( jQuery, window, document );
21572
21573
/*!
21574
 * # Semantic UI 2.2.11 - Visibility

public/lib/semantic/components/state.js 1 location

@@ 11-708 (lines=698) @@
8
 *
9
 */
10
11
;(function ($, window, document, undefined) {
12
13
"use strict";
14
15
window = (typeof window != 'undefined' && window.Math == Math)
16
  ? window
17
  : (typeof self != 'undefined' && self.Math == Math)
18
    ? self
19
    : Function('return this')()
20
;
21
22
$.fn.state = function(parameters) {
23
  var
24
    $allModules     = $(this),
25
26
    moduleSelector  = $allModules.selector || '',
27
28
    hasTouch        = ('ontouchstart' in document.documentElement),
29
    time            = new Date().getTime(),
30
    performance     = [],
31
32
    query           = arguments[0],
33
    methodInvoked   = (typeof query == 'string'),
34
    queryArguments  = [].slice.call(arguments, 1),
35
36
    returnedValue
37
  ;
38
  $allModules
39
    .each(function() {
40
      var
41
        settings          = ( $.isPlainObject(parameters) )
42
          ? $.extend(true, {}, $.fn.state.settings, parameters)
43
          : $.extend({}, $.fn.state.settings),
44
45
        error           = settings.error,
46
        metadata        = settings.metadata,
47
        className       = settings.className,
48
        namespace       = settings.namespace,
49
        states          = settings.states,
50
        text            = settings.text,
51
52
        eventNamespace  = '.' + namespace,
53
        moduleNamespace = namespace + '-module',
54
55
        $module         = $(this),
56
57
        element         = this,
58
        instance        = $module.data(moduleNamespace),
59
60
        module
61
      ;
62
      module = {
63
64
        initialize: function() {
65
          module.verbose('Initializing module');
66
67
          // allow module to guess desired state based on element
68
          if(settings.automatic) {
69
            module.add.defaults();
70
          }
71
72
          // bind events with delegated events
73
          if(settings.context && moduleSelector !== '') {
74
            $(settings.context)
75
              .on(moduleSelector, 'mouseenter' + eventNamespace, module.change.text)
76
              .on(moduleSelector, 'mouseleave' + eventNamespace, module.reset.text)
77
              .on(moduleSelector, 'click'      + eventNamespace, module.toggle.state)
78
            ;
79
          }
80
          else {
81
            $module
82
              .on('mouseenter' + eventNamespace, module.change.text)
83
              .on('mouseleave' + eventNamespace, module.reset.text)
84
              .on('click'      + eventNamespace, module.toggle.state)
85
            ;
86
          }
87
          module.instantiate();
88
        },
89
90
        instantiate: function() {
91
          module.verbose('Storing instance of module', module);
92
          instance = module;
93
          $module
94
            .data(moduleNamespace, module)
95
          ;
96
        },
97
98
        destroy: function() {
99
          module.verbose('Destroying previous module', instance);
100
          $module
101
            .off(eventNamespace)
102
            .removeData(moduleNamespace)
103
          ;
104
        },
105
106
        refresh: function() {
107
          module.verbose('Refreshing selector cache');
108
          $module = $(element);
109
        },
110
111
        add: {
112
          defaults: function() {
113
            var
114
              userStates = parameters && $.isPlainObject(parameters.states)
115
                ? parameters.states
116
                : {}
117
            ;
118
            $.each(settings.defaults, function(type, typeStates) {
119
              if( module.is[type] !== undefined && module.is[type]() ) {
120
                module.verbose('Adding default states', type, element);
121
                $.extend(settings.states, typeStates, userStates);
122
              }
123
            });
124
          }
125
        },
126
127
        is: {
128
129
          active: function() {
130
            return $module.hasClass(className.active);
131
          },
132
          loading: function() {
133
            return $module.hasClass(className.loading);
134
          },
135
          inactive: function() {
136
            return !( $module.hasClass(className.active) );
137
          },
138
          state: function(state) {
139
            if(className[state] === undefined) {
140
              return false;
141
            }
142
            return $module.hasClass( className[state] );
143
          },
144
145
          enabled: function() {
146
            return !( $module.is(settings.filter.active) );
147
          },
148
          disabled: function() {
149
            return ( $module.is(settings.filter.active) );
150
          },
151
          textEnabled: function() {
152
            return !( $module.is(settings.filter.text) );
153
          },
154
155
          // definitions for automatic type detection
156
          button: function() {
157
            return $module.is('.button:not(a, .submit)');
158
          },
159
          input: function() {
160
            return $module.is('input');
161
          },
162
          progress: function() {
163
            return $module.is('.ui.progress');
164
          }
165
        },
166
167
        allow: function(state) {
168
          module.debug('Now allowing state', state);
169
          states[state] = true;
170
        },
171
        disallow: function(state) {
172
          module.debug('No longer allowing', state);
173
          states[state] = false;
174
        },
175
176
        allows: function(state) {
177
          return states[state] || false;
178
        },
179
180
        enable: function() {
181
          $module.removeClass(className.disabled);
182
        },
183
184
        disable: function() {
185
          $module.addClass(className.disabled);
186
        },
187
188
        setState: function(state) {
189
          if(module.allows(state)) {
190
            $module.addClass( className[state] );
191
          }
192
        },
193
194
        removeState: function(state) {
195
          if(module.allows(state)) {
196
            $module.removeClass( className[state] );
197
          }
198
        },
199
200
        toggle: {
201
          state: function() {
202
            var
203
              apiRequest,
204
              requestCancelled
205
            ;
206
            if( module.allows('active') && module.is.enabled() ) {
207
              module.refresh();
208
              if($.fn.api !== undefined) {
209
                apiRequest       = $module.api('get request');
210
                requestCancelled = $module.api('was cancelled');
211
                if( requestCancelled ) {
212
                  module.debug('API Request cancelled by beforesend');
213
                  settings.activateTest   = function(){ return false; };
214
                  settings.deactivateTest = function(){ return false; };
215
                }
216
                else if(apiRequest) {
217
                  module.listenTo(apiRequest);
218
                  return;
219
                }
220
              }
221
              module.change.state();
222
            }
223
          }
224
        },
225
226
        listenTo: function(apiRequest) {
227
          module.debug('API request detected, waiting for state signal', apiRequest);
228
          if(apiRequest) {
229
            if(text.loading) {
230
              module.update.text(text.loading);
231
            }
232
            $.when(apiRequest)
233
              .then(function() {
234
                if(apiRequest.state() == 'resolved') {
235
                  module.debug('API request succeeded');
236
                  settings.activateTest   = function(){ return true; };
237
                  settings.deactivateTest = function(){ return true; };
238
                }
239
                else {
240
                  module.debug('API request failed');
241
                  settings.activateTest   = function(){ return false; };
242
                  settings.deactivateTest = function(){ return false; };
243
                }
244
                module.change.state();
245
              })
246
            ;
247
          }
248
        },
249
250
        // checks whether active/inactive state can be given
251
        change: {
252
253
          state: function() {
254
            module.debug('Determining state change direction');
255
            // inactive to active change
256
            if( module.is.inactive() ) {
257
              module.activate();
258
            }
259
            else {
260
              module.deactivate();
261
            }
262
            if(settings.sync) {
263
              module.sync();
264
            }
265
            settings.onChange.call(element);
266
          },
267
268
          text: function() {
269
            if( module.is.textEnabled() ) {
270
              if(module.is.disabled() ) {
271
                module.verbose('Changing text to disabled text', text.hover);
272
                module.update.text(text.disabled);
273
              }
274
              else if( module.is.active() ) {
275
                if(text.hover) {
276
                  module.verbose('Changing text to hover text', text.hover);
277
                  module.update.text(text.hover);
278
                }
279
                else if(text.deactivate) {
280
                  module.verbose('Changing text to deactivating text', text.deactivate);
281
                  module.update.text(text.deactivate);
282
                }
283
              }
284
              else {
285
                if(text.hover) {
286
                  module.verbose('Changing text to hover text', text.hover);
287
                  module.update.text(text.hover);
288
                }
289
                else if(text.activate){
290
                  module.verbose('Changing text to activating text', text.activate);
291
                  module.update.text(text.activate);
292
                }
293
              }
294
            }
295
          }
296
297
        },
298
299
        activate: function() {
300
          if( settings.activateTest.call(element) ) {
301
            module.debug('Setting state to active');
302
            $module
303
              .addClass(className.active)
304
            ;
305
            module.update.text(text.active);
306
            settings.onActivate.call(element);
307
          }
308
        },
309
310
        deactivate: function() {
311
          if( settings.deactivateTest.call(element) ) {
312
            module.debug('Setting state to inactive');
313
            $module
314
              .removeClass(className.active)
315
            ;
316
            module.update.text(text.inactive);
317
            settings.onDeactivate.call(element);
318
          }
319
        },
320
321
        sync: function() {
322
          module.verbose('Syncing other buttons to current state');
323
          if( module.is.active() ) {
324
            $allModules
325
              .not($module)
326
                .state('activate');
327
          }
328
          else {
329
            $allModules
330
              .not($module)
331
                .state('deactivate')
332
            ;
333
          }
334
        },
335
336
        get: {
337
          text: function() {
338
            return (settings.selector.text)
339
              ? $module.find(settings.selector.text).text()
340
              : $module.html()
341
            ;
342
          },
343
          textFor: function(state) {
344
            return text[state] || false;
345
          }
346
        },
347
348
        flash: {
349
          text: function(text, duration, callback) {
350
            var
351
              previousText = module.get.text()
352
            ;
353
            module.debug('Flashing text message', text, duration);
354
            text     = text     || settings.text.flash;
355
            duration = duration || settings.flashDuration;
356
            callback = callback || function() {};
357
            module.update.text(text);
358
            setTimeout(function(){
359
              module.update.text(previousText);
360
              callback.call(element);
361
            }, duration);
362
          }
363
        },
364
365
        reset: {
366
          // on mouseout sets text to previous value
367
          text: function() {
368
            var
369
              activeText   = text.active   || $module.data(metadata.storedText),
370
              inactiveText = text.inactive || $module.data(metadata.storedText)
371
            ;
372
            if( module.is.textEnabled() ) {
373
              if( module.is.active() && activeText) {
374
                module.verbose('Resetting active text', activeText);
375
                module.update.text(activeText);
376
              }
377
              else if(inactiveText) {
378
                module.verbose('Resetting inactive text', activeText);
379
                module.update.text(inactiveText);
380
              }
381
            }
382
          }
383
        },
384
385
        update: {
386
          text: function(text) {
387
            var
388
              currentText = module.get.text()
389
            ;
390
            if(text && text !== currentText) {
391
              module.debug('Updating text', text);
392
              if(settings.selector.text) {
393
                $module
394
                  .data(metadata.storedText, text)
395
                  .find(settings.selector.text)
396
                    .text(text)
397
                ;
398
              }
399
              else {
400
                $module
401
                  .data(metadata.storedText, text)
402
                  .html(text)
403
                ;
404
              }
405
            }
406
            else {
407
              module.debug('Text is already set, ignoring update', text);
408
            }
409
          }
410
        },
411
412
        setting: function(name, value) {
413
          module.debug('Changing setting', name, value);
414
          if( $.isPlainObject(name) ) {
415
            $.extend(true, settings, name);
416
          }
417
          else if(value !== undefined) {
418
            if($.isPlainObject(settings[name])) {
419
              $.extend(true, settings[name], value);
420
            }
421
            else {
422
              settings[name] = value;
423
            }
424
          }
425
          else {
426
            return settings[name];
427
          }
428
        },
429
        internal: function(name, value) {
430
          if( $.isPlainObject(name) ) {
431
            $.extend(true, module, name);
432
          }
433
          else if(value !== undefined) {
434
            module[name] = value;
435
          }
436
          else {
437
            return module[name];
438
          }
439
        },
440
        debug: function() {
441
          if(!settings.silent && settings.debug) {
442
            if(settings.performance) {
443
              module.performance.log(arguments);
444
            }
445
            else {
446
              module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
447
              module.debug.apply(console, arguments);
448
            }
449
          }
450
        },
451
        verbose: function() {
452
          if(!settings.silent && settings.verbose && settings.debug) {
453
            if(settings.performance) {
454
              module.performance.log(arguments);
455
            }
456
            else {
457
              module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
458
              module.verbose.apply(console, arguments);
459
            }
460
          }
461
        },
462
        error: function() {
463
          if(!settings.silent) {
464
            module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
465
            module.error.apply(console, arguments);
466
          }
467
        },
468
        performance: {
469
          log: function(message) {
470
            var
471
              currentTime,
472
              executionTime,
473
              previousTime
474
            ;
475
            if(settings.performance) {
476
              currentTime   = new Date().getTime();
477
              previousTime  = time || currentTime;
478
              executionTime = currentTime - previousTime;
479
              time          = currentTime;
480
              performance.push({
481
                'Name'           : message[0],
482
                'Arguments'      : [].slice.call(message, 1) || '',
483
                'Element'        : element,
484
                'Execution Time' : executionTime
485
              });
486
            }
487
            clearTimeout(module.performance.timer);
488
            module.performance.timer = setTimeout(module.performance.display, 500);
489
          },
490
          display: function() {
491
            var
492
              title = settings.name + ':',
493
              totalTime = 0
494
            ;
495
            time = false;
496
            clearTimeout(module.performance.timer);
497
            $.each(performance, function(index, data) {
498
              totalTime += data['Execution Time'];
499
            });
500
            title += ' ' + totalTime + 'ms';
501
            if(moduleSelector) {
502
              title += ' \'' + moduleSelector + '\'';
503
            }
504
            if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
505
              console.groupCollapsed(title);
506
              if(console.table) {
507
                console.table(performance);
508
              }
509
              else {
510
                $.each(performance, function(index, data) {
511
                  console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
512
                });
513
              }
514
              console.groupEnd();
515
            }
516
            performance = [];
517
          }
518
        },
519
        invoke: function(query, passedArguments, context) {
520
          var
521
            object = instance,
522
            maxDepth,
523
            found,
524
            response
525
          ;
526
          passedArguments = passedArguments || queryArguments;
527
          context         = element         || context;
528
          if(typeof query == 'string' && object !== undefined) {
529
            query    = query.split(/[\. ]/);
530
            maxDepth = query.length - 1;
531
            $.each(query, function(depth, value) {
532
              var camelCaseValue = (depth != maxDepth)
533
                ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
534
                : query
535
              ;
536
              if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
537
                object = object[camelCaseValue];
538
              }
539
              else if( object[camelCaseValue] !== undefined ) {
540
                found = object[camelCaseValue];
541
                return false;
542
              }
543
              else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
544
                object = object[value];
545
              }
546
              else if( object[value] !== undefined ) {
547
                found = object[value];
548
                return false;
549
              }
550
              else {
551
                module.error(error.method, query);
552
                return false;
553
              }
554
            });
555
          }
556
          if ( $.isFunction( found ) ) {
557
            response = found.apply(context, passedArguments);
558
          }
559
          else if(found !== undefined) {
560
            response = found;
561
          }
562
          if($.isArray(returnedValue)) {
563
            returnedValue.push(response);
564
          }
565
          else if(returnedValue !== undefined) {
566
            returnedValue = [returnedValue, response];
567
          }
568
          else if(response !== undefined) {
569
            returnedValue = response;
570
          }
571
          return found;
572
        }
573
      };
574
575
      if(methodInvoked) {
576
        if(instance === undefined) {
577
          module.initialize();
578
        }
579
        module.invoke(query);
580
      }
581
      else {
582
        if(instance !== undefined) {
583
          instance.invoke('destroy');
584
        }
585
        module.initialize();
586
      }
587
    })
588
  ;
589
590
  return (returnedValue !== undefined)
591
    ? returnedValue
592
    : this
593
  ;
594
};
595
596
$.fn.state.settings = {
597
598
  // module info
599
  name           : 'State',
600
601
  // debug output
602
  debug          : false,
603
604
  // verbose debug output
605
  verbose        : false,
606
607
  // namespace for events
608
  namespace      : 'state',
609
610
  // debug data includes performance
611
  performance    : true,
612
613
  // callback occurs on state change
614
  onActivate     : function() {},
615
  onDeactivate   : function() {},
616
  onChange       : function() {},
617
618
  // state test functions
619
  activateTest   : function() { return true; },
620
  deactivateTest : function() { return true; },
621
622
  // whether to automatically map default states
623
  automatic      : true,
624
625
  // activate / deactivate changes all elements instantiated at same time
626
  sync           : false,
627
628
  // default flash text duration, used for temporarily changing text of an element
629
  flashDuration  : 1000,
630
631
  // selector filter
632
  filter     : {
633
    text   : '.loading, .disabled',
634
    active : '.disabled'
635
  },
636
637
  context    : false,
638
639
  // error
640
  error: {
641
    beforeSend : 'The before send function has cancelled state change',
642
    method     : 'The method you called is not defined.'
643
  },
644
645
  // metadata
646
  metadata: {
647
    promise    : 'promise',
648
    storedText : 'stored-text'
649
  },
650
651
  // change class on state
652
  className: {
653
    active   : 'active',
654
    disabled : 'disabled',
655
    error    : 'error',
656
    loading  : 'loading',
657
    success  : 'success',
658
    warning  : 'warning'
659
  },
660
661
  selector: {
662
    // selector for text node
663
    text: false
664
  },
665
666
  defaults : {
667
    input: {
668
      disabled : true,
669
      loading  : true,
670
      active   : true
671
    },
672
    button: {
673
      disabled : true,
674
      loading  : true,
675
      active   : true,
676
    },
677
    progress: {
678
      active   : true,
679
      success  : true,
680
      warning  : true,
681
      error    : true
682
    }
683
  },
684
685
  states     : {
686
    active   : true,
687
    disabled : true,
688
    error    : true,
689
    loading  : true,
690
    success  : true,
691
    warning  : true
692
  },
693
694
  text     : {
695
    disabled   : false,
696
    flash      : false,
697
    hover      : false,
698
    active     : false,
699
    inactive   : false,
700
    activate   : false,
701
    deactivate : false
702
  }
703
704
};
705
706
707
708
})( jQuery, window, document );
709