site.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*!
  2. * # Fomantic-UI - Site
  3. * http://github.com/fomantic/Fomantic-UI/
  4. *
  5. *
  6. * Released under the MIT license
  7. * http://opensource.org/licenses/MIT
  8. *
  9. */
  10. ;(function ($, window, document, undefined) {
  11. $.isFunction = $.isFunction || function(obj) {
  12. return typeof obj === "function" && typeof obj.nodeType !== "number";
  13. };
  14. $.site = $.fn.site = function(parameters) {
  15. var
  16. time = new Date().getTime(),
  17. performance = [],
  18. query = arguments[0],
  19. methodInvoked = (typeof query == 'string'),
  20. queryArguments = [].slice.call(arguments, 1),
  21. settings = ( $.isPlainObject(parameters) )
  22. ? $.extend(true, {}, $.site.settings, parameters)
  23. : $.extend({}, $.site.settings),
  24. namespace = settings.namespace,
  25. error = settings.error,
  26. moduleNamespace = 'module-' + namespace,
  27. $document = $(document),
  28. $module = $document,
  29. element = this,
  30. instance = $module.data(moduleNamespace),
  31. module,
  32. returnedValue
  33. ;
  34. module = {
  35. initialize: function() {
  36. module.instantiate();
  37. },
  38. instantiate: function() {
  39. module.verbose('Storing instance of site', module);
  40. instance = module;
  41. $module
  42. .data(moduleNamespace, module)
  43. ;
  44. },
  45. normalize: function() {
  46. module.fix.console();
  47. module.fix.requestAnimationFrame();
  48. },
  49. fix: {
  50. console: function() {
  51. module.debug('Normalizing window.console');
  52. if (console === undefined || console.log === undefined) {
  53. module.verbose('Console not available, normalizing events');
  54. module.disable.console();
  55. }
  56. if (typeof console.group == 'undefined' || typeof console.groupEnd == 'undefined' || typeof console.groupCollapsed == 'undefined') {
  57. module.verbose('Console group not available, normalizing events');
  58. window.console.group = function() {};
  59. window.console.groupEnd = function() {};
  60. window.console.groupCollapsed = function() {};
  61. }
  62. if (typeof console.markTimeline == 'undefined') {
  63. module.verbose('Mark timeline not available, normalizing events');
  64. window.console.markTimeline = function() {};
  65. }
  66. },
  67. consoleClear: function() {
  68. module.debug('Disabling programmatic console clearing');
  69. window.console.clear = function() {};
  70. },
  71. requestAnimationFrame: function() {
  72. module.debug('Normalizing requestAnimationFrame');
  73. if(window.requestAnimationFrame === undefined) {
  74. module.debug('RequestAnimationFrame not available, normalizing event');
  75. window.requestAnimationFrame = window.requestAnimationFrame
  76. || window.mozRequestAnimationFrame
  77. || window.webkitRequestAnimationFrame
  78. || window.msRequestAnimationFrame
  79. || function(callback) { setTimeout(callback, 0); }
  80. ;
  81. }
  82. }
  83. },
  84. moduleExists: function(name) {
  85. return ($.fn[name] !== undefined && $.fn[name].settings !== undefined);
  86. },
  87. enabled: {
  88. modules: function(modules) {
  89. var
  90. enabledModules = []
  91. ;
  92. modules = modules || settings.modules;
  93. $.each(modules, function(index, name) {
  94. if(module.moduleExists(name)) {
  95. enabledModules.push(name);
  96. }
  97. });
  98. return enabledModules;
  99. }
  100. },
  101. disabled: {
  102. modules: function(modules) {
  103. var
  104. disabledModules = []
  105. ;
  106. modules = modules || settings.modules;
  107. $.each(modules, function(index, name) {
  108. if(!module.moduleExists(name)) {
  109. disabledModules.push(name);
  110. }
  111. });
  112. return disabledModules;
  113. }
  114. },
  115. change: {
  116. setting: function(setting, value, modules, modifyExisting) {
  117. modules = (typeof modules === 'string')
  118. ? (modules === 'all')
  119. ? settings.modules
  120. : [modules]
  121. : modules || settings.modules
  122. ;
  123. modifyExisting = (modifyExisting !== undefined)
  124. ? modifyExisting
  125. : true
  126. ;
  127. $.each(modules, function(index, name) {
  128. var
  129. namespace = (module.moduleExists(name))
  130. ? $.fn[name].settings.namespace || false
  131. : true,
  132. $existingModules
  133. ;
  134. if(module.moduleExists(name)) {
  135. module.verbose('Changing default setting', setting, value, name);
  136. $.fn[name].settings[setting] = value;
  137. if(modifyExisting && namespace) {
  138. $existingModules = $(':data(module-' + namespace + ')');
  139. if($existingModules.length > 0) {
  140. module.verbose('Modifying existing settings', $existingModules);
  141. $existingModules[name]('setting', setting, value);
  142. }
  143. }
  144. }
  145. });
  146. },
  147. settings: function(newSettings, modules, modifyExisting) {
  148. modules = (typeof modules === 'string')
  149. ? [modules]
  150. : modules || settings.modules
  151. ;
  152. modifyExisting = (modifyExisting !== undefined)
  153. ? modifyExisting
  154. : true
  155. ;
  156. $.each(modules, function(index, name) {
  157. var
  158. $existingModules
  159. ;
  160. if(module.moduleExists(name)) {
  161. module.verbose('Changing default setting', newSettings, name);
  162. $.extend(true, $.fn[name].settings, newSettings);
  163. if(modifyExisting && namespace) {
  164. $existingModules = $(':data(module-' + namespace + ')');
  165. if($existingModules.length > 0) {
  166. module.verbose('Modifying existing settings', $existingModules);
  167. $existingModules[name]('setting', newSettings);
  168. }
  169. }
  170. }
  171. });
  172. }
  173. },
  174. enable: {
  175. console: function() {
  176. module.console(true);
  177. },
  178. debug: function(modules, modifyExisting) {
  179. modules = modules || settings.modules;
  180. module.debug('Enabling debug for modules', modules);
  181. module.change.setting('debug', true, modules, modifyExisting);
  182. },
  183. verbose: function(modules, modifyExisting) {
  184. modules = modules || settings.modules;
  185. module.debug('Enabling verbose debug for modules', modules);
  186. module.change.setting('verbose', true, modules, modifyExisting);
  187. }
  188. },
  189. disable: {
  190. console: function() {
  191. module.console(false);
  192. },
  193. debug: function(modules, modifyExisting) {
  194. modules = modules || settings.modules;
  195. module.debug('Disabling debug for modules', modules);
  196. module.change.setting('debug', false, modules, modifyExisting);
  197. },
  198. verbose: function(modules, modifyExisting) {
  199. modules = modules || settings.modules;
  200. module.debug('Disabling verbose debug for modules', modules);
  201. module.change.setting('verbose', false, modules, modifyExisting);
  202. }
  203. },
  204. console: function(enable) {
  205. if(enable) {
  206. if(instance.cache.console === undefined) {
  207. module.error(error.console);
  208. return;
  209. }
  210. module.debug('Restoring console function');
  211. window.console = instance.cache.console;
  212. }
  213. else {
  214. module.debug('Disabling console function');
  215. instance.cache.console = window.console;
  216. window.console = {
  217. clear : function(){},
  218. error : function(){},
  219. group : function(){},
  220. groupCollapsed : function(){},
  221. groupEnd : function(){},
  222. info : function(){},
  223. log : function(){},
  224. markTimeline : function(){},
  225. warn : function(){}
  226. };
  227. }
  228. },
  229. destroy: function() {
  230. module.verbose('Destroying previous site for', $module);
  231. $module
  232. .removeData(moduleNamespace)
  233. ;
  234. },
  235. cache: {},
  236. setting: function(name, value) {
  237. if( $.isPlainObject(name) ) {
  238. $.extend(true, settings, name);
  239. }
  240. else if(value !== undefined) {
  241. settings[name] = value;
  242. }
  243. else {
  244. return settings[name];
  245. }
  246. },
  247. internal: function(name, value) {
  248. if( $.isPlainObject(name) ) {
  249. $.extend(true, module, name);
  250. }
  251. else if(value !== undefined) {
  252. module[name] = value;
  253. }
  254. else {
  255. return module[name];
  256. }
  257. },
  258. debug: function() {
  259. if(settings.debug) {
  260. if(settings.performance) {
  261. module.performance.log(arguments);
  262. }
  263. else {
  264. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  265. module.debug.apply(console, arguments);
  266. }
  267. }
  268. },
  269. verbose: function() {
  270. if(settings.verbose && settings.debug) {
  271. if(settings.performance) {
  272. module.performance.log(arguments);
  273. }
  274. else {
  275. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  276. module.verbose.apply(console, arguments);
  277. }
  278. }
  279. },
  280. error: function() {
  281. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  282. module.error.apply(console, arguments);
  283. },
  284. performance: {
  285. log: function(message) {
  286. var
  287. currentTime,
  288. executionTime,
  289. previousTime
  290. ;
  291. if(settings.performance) {
  292. currentTime = new Date().getTime();
  293. previousTime = time || currentTime;
  294. executionTime = currentTime - previousTime;
  295. time = currentTime;
  296. performance.push({
  297. 'Element' : element,
  298. 'Name' : message[0],
  299. 'Arguments' : [].slice.call(message, 1) || '',
  300. 'Execution Time' : executionTime
  301. });
  302. }
  303. clearTimeout(module.performance.timer);
  304. module.performance.timer = setTimeout(module.performance.display, 500);
  305. },
  306. display: function() {
  307. var
  308. title = settings.name + ':',
  309. totalTime = 0
  310. ;
  311. time = false;
  312. clearTimeout(module.performance.timer);
  313. $.each(performance, function(index, data) {
  314. totalTime += data['Execution Time'];
  315. });
  316. title += ' ' + totalTime + 'ms';
  317. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  318. console.groupCollapsed(title);
  319. if(console.table) {
  320. console.table(performance);
  321. }
  322. else {
  323. $.each(performance, function(index, data) {
  324. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  325. });
  326. }
  327. console.groupEnd();
  328. }
  329. performance = [];
  330. }
  331. },
  332. invoke: function(query, passedArguments, context) {
  333. var
  334. object = instance,
  335. maxDepth,
  336. found,
  337. response
  338. ;
  339. passedArguments = passedArguments || queryArguments;
  340. context = element || context;
  341. if(typeof query == 'string' && object !== undefined) {
  342. query = query.split(/[\. ]/);
  343. maxDepth = query.length - 1;
  344. $.each(query, function(depth, value) {
  345. var camelCaseValue = (depth != maxDepth)
  346. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  347. : query
  348. ;
  349. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  350. object = object[camelCaseValue];
  351. }
  352. else if( object[camelCaseValue] !== undefined ) {
  353. found = object[camelCaseValue];
  354. return false;
  355. }
  356. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  357. object = object[value];
  358. }
  359. else if( object[value] !== undefined ) {
  360. found = object[value];
  361. return false;
  362. }
  363. else {
  364. module.error(error.method, query);
  365. return false;
  366. }
  367. });
  368. }
  369. if ( $.isFunction( found ) ) {
  370. response = found.apply(context, passedArguments);
  371. }
  372. else if(found !== undefined) {
  373. response = found;
  374. }
  375. if(Array.isArray(returnedValue)) {
  376. returnedValue.push(response);
  377. }
  378. else if(returnedValue !== undefined) {
  379. returnedValue = [returnedValue, response];
  380. }
  381. else if(response !== undefined) {
  382. returnedValue = response;
  383. }
  384. return found;
  385. }
  386. };
  387. if(methodInvoked) {
  388. if(instance === undefined) {
  389. module.initialize();
  390. }
  391. module.invoke(query);
  392. }
  393. else {
  394. if(instance !== undefined) {
  395. module.destroy();
  396. }
  397. module.initialize();
  398. }
  399. return (returnedValue !== undefined)
  400. ? returnedValue
  401. : this
  402. ;
  403. };
  404. $.site.settings = {
  405. name : 'Site',
  406. namespace : 'site',
  407. error : {
  408. console : 'Console cannot be restored, most likely it was overwritten outside of module',
  409. method : 'The method you called is not defined.'
  410. },
  411. debug : false,
  412. verbose : false,
  413. performance : true,
  414. modules: [
  415. 'accordion',
  416. 'api',
  417. 'calendar',
  418. 'checkbox',
  419. 'dimmer',
  420. 'dropdown',
  421. 'embed',
  422. 'form',
  423. 'modal',
  424. 'nag',
  425. 'popup',
  426. 'slider',
  427. 'rating',
  428. 'shape',
  429. 'sidebar',
  430. 'state',
  431. 'sticky',
  432. 'tab',
  433. 'toast',
  434. 'transition',
  435. 'visibility',
  436. 'visit'
  437. ],
  438. siteNamespace : 'site',
  439. namespaceStub : {
  440. cache : {},
  441. config : {},
  442. sections : {},
  443. section : {},
  444. utilities : {}
  445. }
  446. };
  447. // allows for selection of elements with data attributes
  448. $.extend($.expr[ ":" ], {
  449. data: ($.expr.createPseudo)
  450. ? $.expr.createPseudo(function(dataName) {
  451. return function(elem) {
  452. return !!$.data(elem, dataName);
  453. };
  454. })
  455. : function(elem, i, match) {
  456. // support: jQuery < 1.8
  457. return !!$.data(elem, match[ 3 ]);
  458. }
  459. });
  460. })( jQuery, window, document );