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.

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