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.

477 lines
14 KiB

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