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.

651 lines
20 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
  1. /*
  2. * # Semantic - Progress
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2014 Contributor
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ( $, window, document, undefined ) {
  12. "use strict";
  13. $.fn.progress = function(parameters) {
  14. var
  15. $allModules = $(this),
  16. moduleSelector = $allModules.selector || '',
  17. hasTouch = ('ontouchstart' in document.documentElement),
  18. time = new Date().getTime(),
  19. performance = [],
  20. query = arguments[0],
  21. methodInvoked = (typeof query == 'string'),
  22. queryArguments = [].slice.call(arguments, 1),
  23. returnedValue
  24. ;
  25. $allModules
  26. .each(function() {
  27. var
  28. settings = ( $.isPlainObject(parameters) )
  29. ? $.extend(true, {}, $.fn.progress.settings, parameters)
  30. : $.extend({}, $.fn.progress.settings),
  31. className = settings.className,
  32. metadata = settings.metadata,
  33. namespace = settings.namespace,
  34. selector = settings.selector,
  35. error = settings.error,
  36. eventNamespace = '.' + namespace,
  37. moduleNamespace = 'module-' + namespace,
  38. $module = $(this),
  39. $bar = $(this).find(selector.bar),
  40. $progress = $(this).find(selector.progress),
  41. $label = $(this).find(selector.label),
  42. element = this,
  43. instance = $module.data(moduleNamespace),
  44. module
  45. ;
  46. module = {
  47. initialize: function() {
  48. module.debug('Initializing progress', settings);
  49. module.read.metadata();
  50. module.set.initials();
  51. module.instantiate();
  52. },
  53. instantiate: function() {
  54. module.verbose('Storing instance of progress', module);
  55. instance = module;
  56. $module
  57. .data(moduleNamespace, module)
  58. ;
  59. },
  60. destroy: function() {
  61. module.verbose('Destroying previous dropdown for', $module);
  62. $module
  63. .removeData(moduleNamespace)
  64. ;
  65. instance = undefined;
  66. },
  67. reset: function() {
  68. module.set.percent(0);
  69. },
  70. complete: function() {
  71. if(module.percent === undefined || module.percent < 100) {
  72. module.set.percent(100);
  73. }
  74. },
  75. read: {
  76. metadata: function() {
  77. if( $module.data(metadata.percent) ) {
  78. module.verbose('Current percent value set from metadata');
  79. module.percent = $module.data(metadata.percent);
  80. }
  81. if( $module.data(metadata.total) ) {
  82. module.verbose('Total value set from metadata');
  83. module.total = $module.data(metadata.total);
  84. }
  85. if( $module.data(metadata.value) ) {
  86. module.verbose('Current value set from metadata');
  87. module.value = $module.data(metadata.value);
  88. }
  89. },
  90. currentValue: function() {
  91. return (module.value !== undefined)
  92. ? module.value
  93. : false
  94. ;
  95. }
  96. },
  97. increment: function(incrementValue) {
  98. var
  99. total = module.total || false,
  100. edgeValue,
  101. startValue,
  102. newValue
  103. ;
  104. if(total) {
  105. startValue = module.value || 0;
  106. incrementValue = incrementValue || 1;
  107. newValue = startValue + incrementValue;
  108. edgeValue = module.total;
  109. module.debug('Incrementing value by', incrementValue, startValue, edgeValue);
  110. if(newValue > edgeValue ) {
  111. module.debug('Value cannot increment above total', edgeValue);
  112. newValue = edgeValue;
  113. }
  114. module.set.progress(newValue);
  115. }
  116. else {
  117. startValue = module.percent || 0;
  118. incrementValue = incrementValue || module.get.randomValue();
  119. newValue = startValue + incrementValue;
  120. edgeValue = 100;
  121. module.debug('Incrementing percentage by', incrementValue, startValue);
  122. if(newValue > edgeValue ) {
  123. module.debug('Value cannot increment above 100 percent');
  124. newValue = edgeValue;
  125. }
  126. module.set.progress(newValue);
  127. }
  128. },
  129. decrement: function(decrementValue) {
  130. var
  131. total = module.total || false,
  132. edgeValue = 0,
  133. startValue,
  134. newValue
  135. ;
  136. if(total) {
  137. startValue = module.value || 0;
  138. decrementValue = decrementValue || 1;
  139. newValue = startValue - decrementValue;
  140. module.debug('Decrementing value by', decrementValue, startValue);
  141. }
  142. else {
  143. startValue = module.percent || 0;
  144. decrementValue = decrementValue || module.get.randomValue();
  145. newValue = startValue - decrementValue;
  146. module.debug('Decrementing percentage by', decrementValue, startValue);
  147. }
  148. if(newValue < edgeValue) {
  149. module.debug('Value cannot decrement below 0');
  150. newValue = 0;
  151. }
  152. module.set.progress(newValue);
  153. },
  154. get: {
  155. text: function(templateText) {
  156. var
  157. value = module.value || 0,
  158. total = module.total || 0,
  159. percent = module.percent || 0
  160. ;
  161. templateText = templateText || '';
  162. templateText = templateText
  163. .replace('{value}', value)
  164. .replace('{total}', total)
  165. .replace('{percent}', percent)
  166. ;
  167. module.debug('Adding variables to progress bar text', templateText);
  168. return templateText;
  169. },
  170. randomValue: function() {
  171. module.debug('Generating random increment percentage');
  172. return Math.floor((Math.random() * settings.random.max) + settings.random.min);
  173. },
  174. percent: function() {
  175. return module.percent || 0;
  176. },
  177. value: function() {
  178. return module.value || false;
  179. },
  180. total: function() {
  181. return module.total || false;
  182. }
  183. },
  184. is: {
  185. success: function() {
  186. return $module.hasClass(className.success);
  187. },
  188. warning: function() {
  189. return $module.hasClass(className.warning);
  190. },
  191. error: function() {
  192. return $module.hasClass(className.error);
  193. }
  194. },
  195. remove: {
  196. active: function() {
  197. module.verbose('Removing active state');
  198. $module.removeClass(className.active);
  199. },
  200. success: function() {
  201. module.verbose('Removing success state');
  202. $module.removeClass(className.success);
  203. },
  204. warning: function() {
  205. module.verbose('Removing warning state');
  206. $module.removeClass(className.warning);
  207. },
  208. error: function() {
  209. module.verbose('Removing error state');
  210. $module.removeClass(className.error);
  211. }
  212. },
  213. set: {
  214. barWidth: function(value) {
  215. if(value > 100) {
  216. module.error(error.tooHigh, value);
  217. }
  218. $bar
  219. .css('width', value + '%')
  220. ;
  221. },
  222. initials: function() {
  223. if(settings.value) {
  224. module.verbose('Current value set in settings', settings.value);
  225. module.value = settings.value;
  226. }
  227. if(settings.total) {
  228. module.verbose('Current total set in settings', settings.total);
  229. module.total = settings.total;
  230. }
  231. if(settings.percent) {
  232. module.verbose('Current percent set in settings', settings.percent);
  233. module.percent = settings.percent;
  234. }
  235. if(module.percent) {
  236. module.set.percent(module.percent);
  237. }
  238. else if(module.value) {
  239. module.set.progress(module.value);
  240. }
  241. },
  242. percent: function(percent) {
  243. percent = (typeof percent == 'string')
  244. ? +(percent.replace('%', ''))
  245. : percent
  246. ;
  247. if(percent > 0 && percent < 1) {
  248. module.verbose('Module percentage passed as decimal, converting');
  249. percent = percent * 100;
  250. }
  251. // round percentage
  252. if(settings.precision === 0) {
  253. percent = Math.round(percent);
  254. }
  255. else {
  256. percent = Math.round(percent * (10 * settings.precision) / (10 * settings.precision) );
  257. }
  258. module.percent = percent;
  259. if(module.total) {
  260. module.value = Math.round( (percent / 100) * module.total);
  261. }
  262. module.set.barWidth(percent);
  263. module.set.barLabel();
  264. if(percent === 100) {
  265. if(settings.autoSuccess && !(module.is.warning() || module.is.error())) {
  266. module.set.success();
  267. module.debug('Automatically triggering success at 100%');
  268. }
  269. else {
  270. module.remove.active();
  271. }
  272. }
  273. else {
  274. module.set.active();
  275. }
  276. $.proxy(settings.onChange, element)(percent, module.value, module.total);
  277. },
  278. label: function(text) {
  279. text = text || '';
  280. if(text) {
  281. text = module.get.text(text);
  282. module.debug('Setting label to text', text);
  283. $label.text(text);
  284. }
  285. },
  286. barLabel: function(text) {
  287. if(text !== undefined) {
  288. $progress.text( module.get.text(text) );
  289. }
  290. else if(settings.label == 'ratio' && module.total) {
  291. module.debug('Adding ratio to bar label');
  292. $progress.text( module.get.text(settings.text.ratio) );
  293. }
  294. else if(settings.label == 'percent') {
  295. module.debug('Adding percentage to bar label');
  296. $progress.text( module.get.text(settings.text.percent) );
  297. }
  298. },
  299. active: function(text) {
  300. text = text || settings.text.active;
  301. module.debug('Setting active state');
  302. if(settings.showActivity) {
  303. $module.addClass(className.active);
  304. }
  305. module.remove.warning();
  306. module.remove.error();
  307. module.remove.success();
  308. if(text) {
  309. module.set.label(text);
  310. }
  311. $.proxy(settings.onActive, element)(module.value, module.total);
  312. },
  313. success : function(text) {
  314. text = text || settings.text.success;
  315. module.debug('Setting success state');
  316. $module.addClass(className.success);
  317. module.remove.active();
  318. module.remove.warning();
  319. module.remove.error();
  320. module.complete();
  321. if(text) {
  322. module.set.label(text);
  323. }
  324. $.proxy(settings.onSuccess, element)(module.total);
  325. },
  326. warning : function(text) {
  327. text = text || settings.text.warning;
  328. module.debug('Setting warning state');
  329. $module.addClass(className.warning);
  330. module.remove.active();
  331. module.remove.success();
  332. module.remove.error();
  333. module.complete();
  334. if(text) {
  335. module.set.label(text);
  336. }
  337. $.proxy(settings.onWarning, element)(module.value, module.total);
  338. },
  339. error : function(text) {
  340. text = text || settings.text.error;
  341. module.debug('Setting error state');
  342. $module.addClass(className.error);
  343. module.remove.active();
  344. module.remove.success();
  345. module.remove.warning();
  346. module.complete();
  347. if(text) {
  348. module.set.label(text);
  349. }
  350. $.proxy(settings.onError, element)(module.value, module.total);
  351. },
  352. total: function(totalValue) {
  353. module.total = totalValue;
  354. },
  355. progress: function(value) {
  356. var
  357. numericValue = (typeof value === 'string')
  358. ? (value.replace(/[^\d.]/g, '') !== '')
  359. ? +(value.replace(/[^\d.]/g, ''))
  360. : false
  361. : value,
  362. percentComplete
  363. ;
  364. if(!numericValue) {
  365. module.error(error.nonNumeric);
  366. }
  367. if(module.total) {
  368. module.value = numericValue;
  369. percentComplete = (numericValue / module.total) * 100;
  370. module.debug('Calculating percent complete from total', percentComplete);
  371. module.set.percent( percentComplete );
  372. }
  373. else {
  374. percentComplete = numericValue;
  375. module.debug('Setting value to exact percentage value', percentComplete);
  376. module.set.percent( percentComplete );
  377. }
  378. }
  379. },
  380. setting: function(name, value) {
  381. module.debug('Changing setting', name, value);
  382. if( $.isPlainObject(name) ) {
  383. $.extend(true, settings, name);
  384. }
  385. else if(value !== undefined) {
  386. settings[name] = value;
  387. }
  388. else {
  389. return settings[name];
  390. }
  391. },
  392. internal: function(name, value) {
  393. if( $.isPlainObject(name) ) {
  394. $.extend(true, module, name);
  395. }
  396. else if(value !== undefined) {
  397. module[name] = value;
  398. }
  399. else {
  400. return module[name];
  401. }
  402. },
  403. debug: function() {
  404. if(settings.debug) {
  405. if(settings.performance) {
  406. module.performance.log(arguments);
  407. }
  408. else {
  409. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  410. module.debug.apply(console, arguments);
  411. }
  412. }
  413. },
  414. verbose: function() {
  415. if(settings.verbose && settings.debug) {
  416. if(settings.performance) {
  417. module.performance.log(arguments);
  418. }
  419. else {
  420. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  421. module.verbose.apply(console, arguments);
  422. }
  423. }
  424. },
  425. error: function() {
  426. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  427. module.error.apply(console, arguments);
  428. },
  429. performance: {
  430. log: function(message) {
  431. var
  432. currentTime,
  433. executionTime,
  434. previousTime
  435. ;
  436. if(settings.performance) {
  437. currentTime = new Date().getTime();
  438. previousTime = time || currentTime;
  439. executionTime = currentTime - previousTime;
  440. time = currentTime;
  441. performance.push({
  442. 'Name' : message[0],
  443. 'Arguments' : [].slice.call(message, 1) || '',
  444. 'Element' : element,
  445. 'Execution Time' : executionTime
  446. });
  447. }
  448. clearTimeout(module.performance.timer);
  449. module.performance.timer = setTimeout(module.performance.display, 100);
  450. },
  451. display: function() {
  452. var
  453. title = settings.name + ':',
  454. totalTime = 0
  455. ;
  456. time = false;
  457. clearTimeout(module.performance.timer);
  458. $.each(performance, function(index, data) {
  459. totalTime += data['Execution Time'];
  460. });
  461. title += ' ' + totalTime + 'ms';
  462. if(moduleSelector) {
  463. title += ' \'' + moduleSelector + '\'';
  464. }
  465. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  466. console.groupCollapsed(title);
  467. if(console.table) {
  468. console.table(performance);
  469. }
  470. else {
  471. $.each(performance, function(index, data) {
  472. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  473. });
  474. }
  475. console.groupEnd();
  476. }
  477. performance = [];
  478. }
  479. },
  480. invoke: function(query, passedArguments, context) {
  481. var
  482. object = instance,
  483. maxDepth,
  484. found,
  485. response
  486. ;
  487. passedArguments = passedArguments || queryArguments;
  488. context = element || context;
  489. if(typeof query == 'string' && object !== undefined) {
  490. query = query.split(/[\. ]/);
  491. maxDepth = query.length - 1;
  492. $.each(query, function(depth, value) {
  493. var camelCaseValue = (depth != maxDepth)
  494. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  495. : query
  496. ;
  497. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  498. object = object[camelCaseValue];
  499. }
  500. else if( object[camelCaseValue] !== undefined ) {
  501. found = object[camelCaseValue];
  502. return false;
  503. }
  504. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  505. object = object[value];
  506. }
  507. else if( object[value] !== undefined ) {
  508. found = object[value];
  509. return false;
  510. }
  511. else {
  512. module.error(error.method, query);
  513. return false;
  514. }
  515. });
  516. }
  517. if ( $.isFunction( found ) ) {
  518. response = found.apply(context, passedArguments);
  519. }
  520. else if(found !== undefined) {
  521. response = found;
  522. }
  523. if($.isArray(returnedValue)) {
  524. returnedValue.push(response);
  525. }
  526. else if(returnedValue !== undefined) {
  527. returnedValue = [returnedValue, response];
  528. }
  529. else if(response !== undefined) {
  530. returnedValue = response;
  531. }
  532. return found;
  533. }
  534. };
  535. if(methodInvoked) {
  536. if(instance === undefined) {
  537. module.initialize();
  538. }
  539. module.invoke(query);
  540. }
  541. else {
  542. if(instance !== undefined) {
  543. module.destroy();
  544. }
  545. module.initialize();
  546. }
  547. })
  548. ;
  549. return (returnedValue !== undefined)
  550. ? returnedValue
  551. : this
  552. ;
  553. };
  554. $.fn.progress.settings = {
  555. name : 'Progress',
  556. namespace : 'progress',
  557. debug : false,
  558. verbose : true,
  559. performance : true,
  560. random : {
  561. min : 2,
  562. max : 5
  563. },
  564. autoSuccess : true,
  565. showActivity : true,
  566. label : 'percent',
  567. precision : 1,
  568. percent : false,
  569. total : false,
  570. value : false,
  571. onChange : function(percent, value, total){},
  572. onSuccess : function(total){},
  573. onActive : function(value, total){},
  574. onError : function(value, total){},
  575. onWarning : function(value, total){},
  576. error : {
  577. method : 'The method you called is not defined.',
  578. nonNumeric : 'Progress value is non numeric'
  579. },
  580. regExp: {
  581. variable: /\{\$*[A-z0-9]+\}/g
  582. },
  583. metadata: {
  584. percent : 'percent',
  585. total : 'total',
  586. value : 'value'
  587. },
  588. selector : {
  589. bar : '> .bar',
  590. label : '> .label',
  591. progress : '.bar > .progress'
  592. },
  593. text : {
  594. active : false,
  595. error : false,
  596. success : false,
  597. warning : false,
  598. percent : '{percent}%',
  599. ratio : '{value} of {total}'
  600. },
  601. className : {
  602. active : 'active',
  603. error : 'error',
  604. success : 'success',
  605. warning : 'warning'
  606. }
  607. };
  608. })( jQuery, window , document );