setting.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. (function () {
  2. 'use strict';
  3. angular.module('ariaNg').directive('ngSetting', ['$timeout', '$q', 'ariaNgConstants', 'ariaNgLocalizationService', 'aria2SettingService', function ($timeout, $q, ariaNgConstants, ariaNgLocalizationService, aria2SettingService) {
  4. return {
  5. restrict: 'E',
  6. templateUrl: 'views/setting.html',
  7. require: '?ngModel',
  8. replace: true,
  9. scope: {
  10. option: '=',
  11. ngModel: '=',
  12. defaultValue: '=?',
  13. onChangeValue: '&'
  14. },
  15. link: function (scope, element, attrs, ngModel) {
  16. var pendingSaveRequest = null;
  17. var options = {
  18. lazySaveTimeout: ariaNgConstants.lazySaveTimeout,
  19. errorTooltipDelay: ariaNgConstants.errorTooltipDelay
  20. };
  21. angular.extend(options, attrs);
  22. var loadHistory = function () {
  23. if (!scope.option || !scope.option.showHistory) {
  24. return;
  25. }
  26. scope.history = aria2SettingService.getSettingHistory(scope.option.key);
  27. };
  28. var destroyTooltip = function () {
  29. angular.element(element).tooltip('destroy');
  30. };
  31. var showTooltip = function (cause, type, causeParams) {
  32. if (!cause) {
  33. return;
  34. }
  35. $timeout(function () {
  36. var currentValue = scope.optionStatus.getValue();
  37. if (currentValue !== 'failed' && currentValue !== 'error') {
  38. return;
  39. }
  40. angular.element(element).tooltip({
  41. title: ariaNgLocalizationService.getLocalizedText(cause, causeParams),
  42. trigger: 'focus',
  43. placement: 'auto top',
  44. container: element,
  45. template:
  46. '<div class="tooltip' + (type ? ' tooltip-' + type : '') + '" role="tooltip">' +
  47. '<div class="tooltip-arrow"></div>' +
  48. '<div class="tooltip-inner"></div>' +
  49. '</div>'
  50. }).tooltip('show');
  51. }, options.errorTooltipDelay);
  52. };
  53. var getHumanReadableSize = function (size) {
  54. if (!size || parseInt(size).toString() != size) {
  55. return size;
  56. }
  57. var sizeUnits = ['', 'K', 'M', 'G'];
  58. var unitIndex = 0;
  59. for (var i = 0; i < sizeUnits.length; i++) {
  60. if ((size < 1024) || (size % 1024 !== 0)) {
  61. break;
  62. }
  63. size = size / 1024;
  64. unitIndex++;
  65. }
  66. return size + sizeUnits[unitIndex];
  67. };
  68. var getHumanReadableValue = function (value) {
  69. if (scope.option.suffix === 'Bytes') {
  70. return getHumanReadableSize(value);
  71. }
  72. return value;
  73. };
  74. scope.optionStatus = (function () {
  75. var value = 'ready';
  76. return {
  77. getValue: function () {
  78. return value;
  79. },
  80. setReady: function () {
  81. destroyTooltip();
  82. value = 'ready';
  83. },
  84. setPending: function () {
  85. destroyTooltip();
  86. value = 'pending';
  87. },
  88. setSaving: function () {
  89. destroyTooltip();
  90. value = 'pending';
  91. },
  92. setSuccess: function () {
  93. destroyTooltip();
  94. value = 'success';
  95. },
  96. setFailed: function (cause) {
  97. destroyTooltip();
  98. value = 'failed';
  99. showTooltip(cause, 'warning');
  100. },
  101. setError: function (cause, causeParams) {
  102. destroyTooltip();
  103. value = 'error';
  104. showTooltip(cause, 'error', causeParams);
  105. },
  106. getStatusFeedbackStyle: function () {
  107. if (value === 'success') {
  108. return 'has-success';
  109. } else if (value === 'failed') {
  110. return 'has-warning';
  111. } else if (value === 'error') {
  112. return 'has-error';
  113. } else {
  114. return '';
  115. }
  116. },
  117. getStatusIcon: function () {
  118. if (value === 'pending') {
  119. return 'fa-hourglass-start';
  120. } else if (value === 'saving') {
  121. return 'fa-spin fa-pulse fa-spinner';
  122. } else if (value === 'success') {
  123. return 'fa-check';
  124. } else if (value === 'failed') {
  125. return 'fa-exclamation';
  126. } else if (value === 'error') {
  127. return 'fa-times';
  128. } else {
  129. return '';
  130. }
  131. },
  132. isShowStatusIcon: function () {
  133. return this.getStatusIcon() !== '';
  134. }
  135. };
  136. })();
  137. scope.getTotalCount = function () {
  138. if (!scope.optionValue && !angular.isString(scope.optionValue)) {
  139. return 0;
  140. }
  141. return scope.optionValue.split(scope.option.split).length;
  142. };
  143. scope.changeValue = function (optionValue, lazySave) {
  144. if (pendingSaveRequest) {
  145. $timeout.cancel(pendingSaveRequest);
  146. }
  147. scope.optionValue = optionValue;
  148. scope.optionStatus.setReady();
  149. if (!scope.option || !scope.option.key || scope.option.readonly) {
  150. return;
  151. }
  152. if (scope.option.required && optionValue === '') {
  153. scope.optionStatus.setError('Option value cannot be empty!');
  154. return;
  155. }
  156. if (optionValue !== '' && scope.option.type === 'integer' && !/^-?\d+$/.test(optionValue)) {
  157. scope.optionStatus.setError('Input number is invalid!');
  158. return;
  159. }
  160. if (optionValue !== '' && scope.option.type === 'float' && !/^-?(\d*\.)?\d+$/.test(optionValue)) {
  161. scope.optionStatus.setError('Input number is invalid!');
  162. return;
  163. }
  164. if (optionValue !== '' && (scope.option.type === 'integer' || scope.option.type === 'float') && (angular.isDefined(scope.option.min) || angular.isDefined(scope.option.max))) {
  165. var number = optionValue;
  166. if (scope.option.type === 'integer') {
  167. number = parseInt(optionValue);
  168. } else if (scope.option.type === 'float') {
  169. number = parseFloat(optionValue);
  170. }
  171. if (angular.isDefined(scope.option.min) && number < scope.option.min) {
  172. scope.optionStatus.setError('Input number is below min value!', { value: scope.option.min });
  173. return;
  174. }
  175. if (angular.isDefined(scope.option.max) && number > scope.option.max) {
  176. scope.optionStatus.setError('Input number is above max value!', { value: scope.option.max });
  177. return;
  178. }
  179. }
  180. if (optionValue !== '' && angular.isDefined(scope.option.pattern) && !(new RegExp(scope.option.pattern).test(optionValue))) {
  181. scope.optionStatus.setError('Input value is invalid!');
  182. return;
  183. }
  184. var data = {
  185. key: scope.option.key,
  186. value: optionValue,
  187. optionStatus: scope.optionStatus
  188. };
  189. var invokeChange = function () {
  190. scope.optionStatus.setSaving();
  191. scope.onChangeValue(data);
  192. };
  193. if (scope.onChangeValue) {
  194. if (lazySave) {
  195. scope.optionStatus.setPending();
  196. pendingSaveRequest = $timeout(function () {
  197. invokeChange();
  198. }, options.lazySaveTimeout);
  199. } else {
  200. invokeChange();
  201. }
  202. }
  203. };
  204. scope.filterHistory = function (userInput) {
  205. var result = [];
  206. if (scope.history && userInput) {
  207. for (var i = 0; i < scope.history.length; i++) {
  208. if (scope.history[i].indexOf(userInput) === 0) {
  209. result.push(scope.history[i]);
  210. }
  211. }
  212. }
  213. return $q.resolve(result);
  214. };
  215. if (ngModel) {
  216. scope.$watch(function () {
  217. return ngModel.$viewValue;
  218. }, function (value) {
  219. scope.optionValue = getHumanReadableValue(value);
  220. });
  221. }
  222. scope.$watch('option', function () {
  223. loadHistory();
  224. element.find('[data-toggle="popover"]').popover();
  225. });
  226. scope.$watch('defaultValue', function (value) {
  227. var displayValue = value;
  228. if (scope.option && scope.option.options) {
  229. for (var i = 0; i < scope.option.options.length; i++) {
  230. var optionItem = scope.option.options[i];
  231. if (optionItem.value === value) {
  232. displayValue = optionItem.name;
  233. break;
  234. }
  235. }
  236. }
  237. scope.placeholder = getHumanReadableValue(displayValue);
  238. });
  239. loadHistory();
  240. }
  241. };
  242. }]);
  243. }());