You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

476 lines
14 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*!
  2. * # Semantic UI 2.0.0 - Nag
  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. ;(function ($, window, document, undefined) {
  12. "use strict";
  13. $.fn.nag = function(parameters) {
  14. var
  15. $allModules = $(this),
  16. moduleSelector = $allModules.selector || '',
  17. time = new Date().getTime(),
  18. performance = [],
  19. query = arguments[0],
  20. methodInvoked = (typeof query == 'string'),
  21. queryArguments = [].slice.call(arguments, 1),
  22. returnedValue
  23. ;
  24. $allModules
  25. .each(function() {
  26. var
  27. settings = ( $.isPlainObject(parameters) )
  28. ? $.extend(true, {}, $.fn.nag.settings, parameters)
  29. : $.extend({}, $.fn.nag.settings),
  30. className = settings.className,
  31. selector = settings.selector,
  32. error = settings.error,
  33. namespace = settings.namespace,
  34. eventNamespace = '.' + namespace,
  35. moduleNamespace = namespace + '-module',
  36. $module = $(this),
  37. $close = $module.find(selector.close),
  38. $context = (settings.context)
  39. ? $(settings.context)
  40. : $('body'),
  41. element = this,
  42. instance = $module.data(moduleNamespace),
  43. moduleOffset,
  44. moduleHeight,
  45. contextWidth,
  46. contextHeight,
  47. contextOffset,
  48. yOffset,
  49. yPosition,
  50. timer,
  51. module,
  52. requestAnimationFrame = window.requestAnimationFrame
  53. || window.mozRequestAnimationFrame
  54. || window.webkitRequestAnimationFrame
  55. || window.msRequestAnimationFrame
  56. || function(callback) { setTimeout(callback, 0); }
  57. ;
  58. module = {
  59. initialize: function() {
  60. module.verbose('Initializing element');
  61. $module
  62. .on('click' + eventNamespace, selector.close, module.dismiss)
  63. .data(moduleNamespace, module)
  64. ;
  65. if(settings.detachable && $module.parent()[0] !== $context[0]) {
  66. $module
  67. .detach()
  68. .prependTo($context)
  69. ;
  70. }
  71. if(settings.displayTime > 0) {
  72. setTimeout(module.hide, settings.displayTime);
  73. }
  74. module.show();
  75. },
  76. destroy: function() {
  77. module.verbose('Destroying instance');
  78. $module
  79. .removeData(moduleNamespace)
  80. .off(eventNamespace)
  81. ;
  82. },
  83. show: function() {
  84. if( module.should.show() && !$module.is(':visible') ) {
  85. module.debug('Showing nag', settings.animation.show);
  86. if(settings.animation.show == 'fade') {
  87. $module
  88. .fadeIn(settings.duration, settings.easing)
  89. ;
  90. }
  91. else {
  92. $module
  93. .slideDown(settings.duration, settings.easing)
  94. ;
  95. }
  96. }
  97. },
  98. hide: function() {
  99. module.debug('Showing nag', settings.animation.hide);
  100. if(settings.animation.show == 'fade') {
  101. $module
  102. .fadeIn(settings.duration, settings.easing)
  103. ;
  104. }
  105. else {
  106. $module
  107. .slideUp(settings.duration, settings.easing)
  108. ;
  109. }
  110. },
  111. onHide: function() {
  112. module.debug('Removing nag', settings.animation.hide);
  113. $module.remove();
  114. if (settings.onHide) {
  115. settings.onHide();
  116. }
  117. },
  118. dismiss: function(event) {
  119. if(settings.storageMethod) {
  120. module.storage.set(settings.key, settings.value);
  121. }
  122. module.hide();
  123. event.stopImmediatePropagation();
  124. event.preventDefault();
  125. },
  126. should: {
  127. show: function() {
  128. if(settings.persist) {
  129. module.debug('Persistent nag is set, can show nag');
  130. return true;
  131. }
  132. if( module.storage.get(settings.key) != settings.value.toString() ) {
  133. module.debug('Stored value is not set, can show nag', module.storage.get(settings.key));
  134. return true;
  135. }
  136. module.debug('Stored value is set, cannot show nag', module.storage.get(settings.key));
  137. return false;
  138. }
  139. },
  140. get: {
  141. storageOptions: function() {
  142. var
  143. options = {}
  144. ;
  145. if(settings.expires) {
  146. options.expires = settings.expires;
  147. }
  148. if(settings.domain) {
  149. options.domain = settings.domain;
  150. }
  151. if(settings.path) {
  152. options.path = settings.path;
  153. }
  154. return options;
  155. }
  156. },
  157. clear: function() {
  158. module.storage.remove(settings.key);
  159. },
  160. storage: {
  161. set: function(key, value) {
  162. var
  163. options = module.get.storageOptions()
  164. ;
  165. if(settings.storageMethod == 'localstorage' && window.localStorage !== undefined) {
  166. window.localStorage.setItem(key, value);
  167. module.debug('Value stored using local storage', key, value);
  168. }
  169. else if($.cookie !== undefined) {
  170. $.cookie(key, value, options);
  171. module.debug('Value stored using cookie', key, value, options);
  172. }
  173. else {
  174. module.error(error.noCookieStorage);
  175. return;
  176. }
  177. },
  178. get: function(key, value) {
  179. var
  180. storedValue
  181. ;
  182. if(settings.storageMethod == 'localstorage' && window.localStorage !== undefined) {
  183. storedValue = window.localStorage.getItem(key);
  184. }
  185. // get by cookie
  186. else if($.cookie !== undefined) {
  187. storedValue = $.cookie(key);
  188. }
  189. else {
  190. module.error(error.noCookieStorage);
  191. }
  192. if(storedValue == 'undefined' || storedValue == 'null' || storedValue === undefined || storedValue === null) {
  193. storedValue = undefined;
  194. }
  195. return storedValue;
  196. },
  197. remove: function(key) {
  198. var
  199. options = module.get.storageOptions()
  200. ;
  201. if(settings.storageMethod == 'local' && window.store !== undefined) {
  202. window.localStorage.removeItem(key);
  203. }
  204. // store by cookie
  205. else if($.cookie !== undefined) {
  206. $.removeCookie(key, options);
  207. }
  208. else {
  209. module.error(error.noStorage);
  210. }
  211. }
  212. },
  213. setting: function(name, value) {
  214. module.debug('Changing setting', name, value);
  215. if( $.isPlainObject(name) ) {
  216. $.extend(true, settings, name);
  217. }
  218. else if(value !== undefined) {
  219. settings[name] = value;
  220. }
  221. else {
  222. return settings[name];
  223. }
  224. },
  225. internal: function(name, value) {
  226. if( $.isPlainObject(name) ) {
  227. $.extend(true, module, name);
  228. }
  229. else if(value !== undefined) {
  230. module[name] = value;
  231. }
  232. else {
  233. return module[name];
  234. }
  235. },
  236. debug: function() {
  237. if(settings.debug) {
  238. if(settings.performance) {
  239. module.performance.log(arguments);
  240. }
  241. else {
  242. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  243. module.debug.apply(console, arguments);
  244. }
  245. }
  246. },
  247. verbose: function() {
  248. if(settings.verbose && settings.debug) {
  249. if(settings.performance) {
  250. module.performance.log(arguments);
  251. }
  252. else {
  253. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  254. module.verbose.apply(console, arguments);
  255. }
  256. }
  257. },
  258. error: function() {
  259. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  260. module.error.apply(console, arguments);
  261. },
  262. performance: {
  263. log: function(message) {
  264. var
  265. currentTime,
  266. executionTime,
  267. previousTime
  268. ;
  269. if(settings.performance) {
  270. currentTime = new Date().getTime();
  271. previousTime = time || currentTime;
  272. executionTime = currentTime - previousTime;
  273. time = currentTime;
  274. performance.push({
  275. 'Name' : message[0],
  276. 'Arguments' : [].slice.call(message, 1) || '',
  277. 'Element' : element,
  278. 'Execution Time' : executionTime
  279. });
  280. }
  281. clearTimeout(module.performance.timer);
  282. module.performance.timer = setTimeout(module.performance.display, 500);
  283. },
  284. display: function() {
  285. var
  286. title = settings.name + ':',
  287. totalTime = 0
  288. ;
  289. time = false;
  290. clearTimeout(module.performance.timer);
  291. $.each(performance, function(index, data) {
  292. totalTime += data['Execution Time'];
  293. });
  294. title += ' ' + totalTime + 'ms';
  295. if(moduleSelector) {
  296. title += ' \'' + moduleSelector + '\'';
  297. }
  298. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  299. console.groupCollapsed(title);
  300. if(console.table) {
  301. console.table(performance);
  302. }
  303. else {
  304. $.each(performance, function(index, data) {
  305. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  306. });
  307. }
  308. console.groupEnd();
  309. }
  310. performance = [];
  311. }
  312. },
  313. invoke: function(query, passedArguments, context) {
  314. var
  315. object = instance,
  316. maxDepth,
  317. found,
  318. response
  319. ;
  320. passedArguments = passedArguments || queryArguments;
  321. context = element || context;
  322. if(typeof query == 'string' && object !== undefined) {
  323. query = query.split(/[\. ]/);
  324. maxDepth = query.length - 1;
  325. $.each(query, function(depth, value) {
  326. var camelCaseValue = (depth != maxDepth)
  327. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  328. : query
  329. ;
  330. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  331. object = object[camelCaseValue];
  332. }
  333. else if( object[camelCaseValue] !== undefined ) {
  334. found = object[camelCaseValue];
  335. return false;
  336. }
  337. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  338. object = object[value];
  339. }
  340. else if( object[value] !== undefined ) {
  341. found = object[value];
  342. return false;
  343. }
  344. else {
  345. module.error(error.method, query);
  346. return false;
  347. }
  348. });
  349. }
  350. if ( $.isFunction( found ) ) {
  351. response = found.apply(context, passedArguments);
  352. }
  353. else if(found !== undefined) {
  354. response = found;
  355. }
  356. if($.isArray(returnedValue)) {
  357. returnedValue.push(response);
  358. }
  359. else if(returnedValue !== undefined) {
  360. returnedValue = [returnedValue, response];
  361. }
  362. else if(response !== undefined) {
  363. returnedValue = response;
  364. }
  365. return found;
  366. }
  367. };
  368. if(methodInvoked) {
  369. if(instance === undefined) {
  370. module.initialize();
  371. }
  372. module.invoke(query);
  373. }
  374. else {
  375. if(instance !== undefined) {
  376. instance.invoke('destroy');
  377. }
  378. module.initialize();
  379. }
  380. })
  381. ;
  382. return (returnedValue !== undefined)
  383. ? returnedValue
  384. : this
  385. ;
  386. };
  387. $.fn.nag.settings = {
  388. name : 'Nag',
  389. debug : false,
  390. verbose : false,
  391. performance : true,
  392. namespace : 'Nag',
  393. // allows cookie to be overriden
  394. persist : false,
  395. // set to zero to require manually dismissal, otherwise hides on its own
  396. displayTime : 0,
  397. animation : {
  398. show : 'slide',
  399. hide : 'slide'
  400. },
  401. context : false,
  402. detachable : false,
  403. expires : 30,
  404. domain : false,
  405. path : '/',
  406. // type of storage to use
  407. storageMethod : 'cookie',
  408. // value to store in dismissed localstorage/cookie
  409. key : 'nag',
  410. value : 'dismiss',
  411. error: {
  412. noCookieStorage : '$.cookie is not included. A storage solution is required.',
  413. noStorage : 'Neither $.cookie or store is defined. A storage solution is required for storing state',
  414. method : 'The method you called is not defined.'
  415. },
  416. className : {
  417. bottom : 'bottom',
  418. fixed : 'fixed'
  419. },
  420. selector : {
  421. close : '.close.icon'
  422. },
  423. speed : 500,
  424. easing : 'easeOutQuad',
  425. onHide: function() {}
  426. };
  427. })( jQuery, window , document );