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.

784 lines
25 KiB

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