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.

620 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
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
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. var Gogits = {};
  2. (function ($) {
  3. // extend jQuery ajax, set csrf token value
  4. var ajax = $.ajax;
  5. $.extend({
  6. ajax: function (url, options) {
  7. if (typeof url === 'object') {
  8. options = url;
  9. url = undefined;
  10. }
  11. options = options || {};
  12. url = options.url;
  13. var csrftoken = $('meta[name=_csrf]').attr('content');
  14. var headers = options.headers || {};
  15. var domain = document.domain.replace(/\./ig, '\\.');
  16. if (!/^(http:|https:).*/.test(url) || eval('/^(http:|https:)\\/\\/(.+\\.)*' + domain + '.*/').test(url)) {
  17. headers = $.extend(headers, {'X-Csrf-Token': csrftoken});
  18. }
  19. options.headers = headers;
  20. var callback = options.success;
  21. options.success = function (data) {
  22. if (data.once) {
  23. // change all _once value if ajax data.once exist
  24. $('[name=_once]').val(data.once);
  25. }
  26. if (callback) {
  27. callback.apply(this, arguments);
  28. }
  29. };
  30. return ajax(url, options);
  31. },
  32. changeHash: function (hash) {
  33. if (history.pushState) {
  34. history.pushState(null, null, hash);
  35. }
  36. else {
  37. location.hash = hash;
  38. }
  39. },
  40. deSelect: function () {
  41. if (window.getSelection) {
  42. window.getSelection().removeAllRanges();
  43. } else {
  44. document.selection.empty();
  45. }
  46. }
  47. });
  48. $.fn.extend({
  49. toggleHide: function () {
  50. $(this).addClass("hidden");
  51. },
  52. toggleShow: function () {
  53. $(this).removeClass("hidden");
  54. },
  55. toggleAjax: function (successCallback) {
  56. var url = $(this).data("ajax");
  57. var method = $(this).data('ajax-method') || 'get';
  58. var ajaxName = $(this).data('ajax-name');
  59. var data = {};
  60. if (ajaxName.endsWith("preview")) {
  61. data["mode"] = "gfm";
  62. data["context"] = $(this).data('ajax-context');
  63. }
  64. $('[data-ajax-rel=' + ajaxName + ']').each(function () {
  65. var field = $(this).data("ajax-field");
  66. var t = $(this).data("ajax-val");
  67. if (t == "val") {
  68. data[field] = $(this).val();
  69. return true;
  70. }
  71. if (t == "txt") {
  72. data[field] = $(this).text();
  73. return true;
  74. }
  75. if (t == "html") {
  76. data[field] = $(this).html();
  77. return true;
  78. }
  79. if (t == "data") {
  80. data[field] = $(this).data("ajax-data");
  81. return true;
  82. }
  83. return true;
  84. });
  85. $.ajax({
  86. url: url,
  87. method: method.toUpperCase(),
  88. data: data,
  89. success: function (d) {
  90. if (successCallback) {
  91. successCallback(d);
  92. }
  93. }
  94. })
  95. }
  96. })
  97. }(jQuery));
  98. (function ($) {
  99. Gogits.showTab = function (selector, index) {
  100. if (!index) {
  101. index = 0;
  102. }
  103. $(selector).tab("show");
  104. $(selector).find("li:eq(" + index + ") a").tab("show");
  105. };
  106. Gogits.validateForm = function (selector, options) {
  107. var $form = $(selector);
  108. options = options || {};
  109. options.showErrors = function (map, list) {
  110. var $error = $form.find('.form-error').addClass('hidden');
  111. $('.has-error').removeClass("has-error");
  112. $error.text(list[0].message).show().removeClass("hidden");
  113. $(list[0].element).parents(".form-group").addClass("has-error");
  114. };
  115. $form.validate(options);
  116. };
  117. // ----- init elements
  118. Gogits.initModals = function () {
  119. var modals = $("[data-toggle=modal]");
  120. if (modals.length < 1) {
  121. return;
  122. }
  123. $.each(modals, function (i, item) {
  124. var hide = $(item).data('modal');
  125. $(item).modal(hide ? hide : "hide");
  126. });
  127. };
  128. Gogits.initTooltips = function () {
  129. $("body").tooltip({
  130. selector: "[data-toggle=tooltip]"
  131. //container: "body"
  132. });
  133. };
  134. Gogits.initPopovers = function () {
  135. var hideAllPopovers = function () {
  136. $('[data-toggle=popover]').each(function () {
  137. $(this).popover('hide');
  138. });
  139. };
  140. $(document).on('click', function (e) {
  141. var $e = $(e.target);
  142. if ($e.data('toggle') == 'popover' || $e.parents("[data-toggle=popover], .popover").length > 0) {
  143. return;
  144. }
  145. hideAllPopovers();
  146. });
  147. $("body").popover({
  148. selector: "[data-toggle=popover]"
  149. });
  150. };
  151. Gogits.initTabs = function () {
  152. var $tabs = $('[data-init=tabs]');
  153. $tabs.tab("show");
  154. $tabs.find("li:eq(0) a").tab("show");
  155. };
  156. // fix dropdown inside click
  157. Gogits.initDropDown = function () {
  158. $('.dropdown-menu.no-propagation').on('click', function (e) {
  159. e.stopPropagation();
  160. });
  161. };
  162. // render markdown
  163. Gogits.renderMarkdown = function () {
  164. var $md = $('.markdown');
  165. var $pre = $md.find('pre > code').parent();
  166. $pre.addClass('prettyprint linenums');
  167. prettyPrint();
  168. // Set anchor.
  169. var headers = {};
  170. $md.find('h1, h2, h3, h4, h5, h6').each(function () {
  171. var node = $(this);
  172. var val = encodeURIComponent(node.text().toLowerCase().replace(/[^\w\- ]/g, '').replace(/[ ]/g, '-'));
  173. var name = val;
  174. if (headers[val] > 0) {
  175. name = val + '-' + headers[val];
  176. }
  177. if (headers[val] == undefined) {
  178. headers[val] = 1;
  179. } else {
  180. headers[val] += 1;
  181. }
  182. node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>');
  183. node.append('<a class="anchor" href="#' + name + '"><span class="octicon octicon-link"></span></a>');
  184. });
  185. };
  186. // render code view
  187. Gogits.renderCodeView = function () {
  188. function selectRange($list, $select, $from) {
  189. $list.removeClass('active');
  190. if ($from) {
  191. var a = parseInt($select.attr('rel').substr(1));
  192. var b = parseInt($from.attr('rel').substr(1));
  193. var c;
  194. if (a != b) {
  195. if (a > b) {
  196. c = a;
  197. a = b;
  198. b = c;
  199. }
  200. var classes = [];
  201. for (i = a; i <= b; i++) {
  202. classes.push('.L' + i);
  203. }
  204. $list.filter(classes.join(',')).addClass('active');
  205. $.changeHash('#L' + a + '-' + 'L' + b);
  206. return
  207. }
  208. }
  209. $select.addClass('active');
  210. $.changeHash('#' + $select.attr('rel'));
  211. }
  212. $(document).on('click', '.lines-num span', function (e) {
  213. var $select = $(this);
  214. var $list = $select.parent().siblings('.lines-code').find('ol.linenums > li');
  215. selectRange($list, $list.filter('[rel=' + $select.attr('rel') + ']'), (e.shiftKey ? $list.filter('.active').eq(0) : null));
  216. $.deSelect();
  217. });
  218. $('.code-view .lines-code > pre').each(function () {
  219. var $pre = $(this);
  220. var $lineCode = $pre.parent();
  221. var $lineNums = $lineCode.siblings('.lines-num');
  222. if ($lineNums.length > 0) {
  223. var nums = $pre.find('ol.linenums > li').length;
  224. for (var i = 1; i <= nums; i++) {
  225. $lineNums.append('<span id="L' + i + '" rel="L' + i + '">' + i + '</span>');
  226. }
  227. }
  228. });
  229. $(window).on('hashchange', function (e) {
  230. var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/);
  231. var $list = $('.code-view ol.linenums > li');
  232. if (m) {
  233. var $first = $list.filter('.' + m[1]);
  234. selectRange($list, $first, $list.filter('.' + m[2]));
  235. $("html, body").scrollTop($first.offset().top - 200);
  236. return;
  237. }
  238. m = window.location.hash.match(/^#(L\d+)$/);
  239. if (m) {
  240. var $first = $list.filter('.' + m[1]);
  241. selectRange($list, $first);
  242. $("html, body").scrollTop($first.offset().top - 200);
  243. }
  244. }).trigger('hashchange');
  245. };
  246. // copy utils
  247. Gogits.bindCopy = function (selector) {
  248. if ($(selector).hasClass('js-copy-bind')) {
  249. return;
  250. }
  251. $(selector).zclip({
  252. path: "/js/ZeroClipboard.swf",
  253. copy: function () {
  254. var t = $(this).data("copy-val");
  255. var to = $($(this).data("copy-from"));
  256. var str = "";
  257. if (t == "txt") {
  258. str = to.text();
  259. }
  260. if (t == 'val') {
  261. str = to.val();
  262. }
  263. if (t == 'html') {
  264. str = to.html();
  265. }
  266. return str;
  267. },
  268. afterCopy: function () {
  269. var $this = $(this);
  270. $this.tooltip('hide')
  271. .attr('data-original-title', 'Copied OK');
  272. setTimeout(function () {
  273. $this.tooltip("show");
  274. }, 200);
  275. setTimeout(function () {
  276. $this.tooltip('hide')
  277. .attr('data-original-title', 'Copy to Clipboard');
  278. }, 3000);
  279. }
  280. }).addClass("js-copy-bind");
  281. }
  282. })(jQuery);
  283. // ajax utils
  284. (function ($) {
  285. Gogits.ajaxDelete = function (url, data, success) {
  286. data = data || {};
  287. data._method = "DELETE";
  288. $.ajax({
  289. url: url,
  290. data: data,
  291. method: "POST",
  292. dataType: "json",
  293. success: function (json) {
  294. if (success) {
  295. success(json);
  296. }
  297. }
  298. })
  299. }
  300. })(jQuery);
  301. function initCore() {
  302. Gogits.initTooltips();
  303. Gogits.initPopovers();
  304. Gogits.initTabs();
  305. Gogits.initModals();
  306. Gogits.initDropDown();
  307. Gogits.renderMarkdown();
  308. Gogits.renderCodeView();
  309. }
  310. function initUserSetting() {
  311. // ssh confirmation
  312. $('#ssh-keys .delete').confirmation({
  313. singleton: true,
  314. onConfirm: function (e, $this) {
  315. Gogits.ajaxDelete("", {"id": $this.data("del")}, function (json) {
  316. if (json.ok) {
  317. window.location.reload();
  318. } else {
  319. alert(json.err);
  320. }
  321. });
  322. }
  323. });
  324. // profile form
  325. (function () {
  326. $('#user-setting-username').on("keyup", function () {
  327. var $this = $(this);
  328. if ($this.val() != $this.attr('title')) {
  329. $this.next('.help-block').toggleShow();
  330. } else {
  331. $this.next('.help-block').toggleHide();
  332. }
  333. });
  334. }())
  335. }
  336. function initRepository() {
  337. // clone group button script
  338. (function () {
  339. var $clone = $('.clone-group-btn');
  340. if ($clone.length) {
  341. var $url = $('.clone-group-url');
  342. $clone.find('button[data-link]').on("click", function (e) {
  343. var $this = $(this);
  344. if (!$this.hasClass('btn-primary')) {
  345. $clone.find('.input-group-btn .btn-primary').removeClass('btn-primary').addClass("btn-default");
  346. $(this).addClass('btn-primary').removeClass('btn-default');
  347. $url.val($this.data("link"));
  348. $clone.find('span.clone-url').text($this.data('link'));
  349. }
  350. }).eq(0).trigger("click");
  351. $("#repo-clone").on("shown.bs.dropdown", function () {
  352. Gogits.bindCopy("[data-init=copy]");
  353. });
  354. Gogits.bindCopy("[data-init=copy]:visible");
  355. }
  356. })();
  357. // watching script
  358. (function () {
  359. var $watch = $('#repo-watching'),
  360. watchLink = $watch.data("watch"),
  361. unwatchLink = $watch.data("unwatch");
  362. $watch.on('click', '.to-watch', function () {
  363. if ($watch.hasClass("watching")) {
  364. return false;
  365. }
  366. $.get(watchLink, function (json) {
  367. if (json.ok) {
  368. $watch.find('.text-primary').removeClass('text-primary');
  369. $watch.find('.to-watch h4').addClass('text-primary');
  370. $watch.find('.fa-eye-slash').removeClass('fa-eye-slash').addClass('fa-eye');
  371. $watch.removeClass("no-watching").addClass("watching");
  372. }
  373. });
  374. return false;
  375. }).on('click', '.to-unwatch', function () {
  376. if ($watch.hasClass("no-watching")) {
  377. return false;
  378. }
  379. $.get(unwatchLink, function (json) {
  380. if (json.ok) {
  381. $watch.find('.text-primary').removeClass('text-primary');
  382. $watch.find('.to-unwatch h4').addClass('text-primary');
  383. $watch.find('.fa-eye').removeClass('fa-eye').addClass('fa-eye-slash');
  384. $watch.removeClass("watching").addClass("no-watching");
  385. }
  386. });
  387. return false;
  388. });
  389. })();
  390. // repo diff counter
  391. (function () {
  392. var $counter = $('.diff-counter');
  393. if ($counter.length < 1) {
  394. return;
  395. }
  396. $counter.each(function (i, item) {
  397. var $item = $(item);
  398. var addLine = $item.find('span[data-line].add').data("line");
  399. var delLine = $item.find('span[data-line].del').data("line");
  400. var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100;
  401. $item.find(".bar .add").css("width", addPercent + "%");
  402. });
  403. }());
  404. // repo setting form
  405. (function () {
  406. $('#repo-setting-name').on("keyup", function () {
  407. var $this = $(this);
  408. if ($this.val() != $this.attr('title')) {
  409. $this.next('.help-block').toggleShow();
  410. } else {
  411. $this.next('.help-block').toggleHide();
  412. }
  413. });
  414. }())
  415. }
  416. function initInstall() {
  417. // database type change
  418. (function () {
  419. var mysql_default = '127.0.0.1:3306'
  420. var postgres_default = '127.0.0.1:5432'
  421. $('#install-database').on("change", function () {
  422. var val = $(this).val();
  423. if (val != "SQLite3") {
  424. $('.server-sql').show();
  425. $('.sqlite-setting').addClass("hide");
  426. if (val == "PostgreSQL") {
  427. $('.pgsql-setting').removeClass("hide");
  428. // Change the host value to the Postgres default, but only
  429. // if the user hasn't already changed it from the MySQL
  430. // default.
  431. if ($('#database-host').val() == mysql_default) {
  432. $('#database-host').val(postgres_default);
  433. }
  434. } else if (val == 'MySQL') {
  435. $('.pgsql-setting').addClass("hide");
  436. if ($('#database-host').val() == postgres_default) {
  437. $('#database-host').val(mysql_default);
  438. }
  439. } else {
  440. $('.pgsql-setting').addClass("hide");
  441. }
  442. } else {
  443. $('.server-sql').hide();
  444. $('.sqlite-setting').removeClass("hide");
  445. }
  446. });
  447. }());
  448. }
  449. function initIssue() {
  450. // close button
  451. (function () {
  452. var $closeBtn = $('#issue-close-btn');
  453. var $openBtn = $('#issue-open-btn');
  454. $('#issue-reply-content').on("keyup", function () {
  455. if ($(this).val().length) {
  456. $closeBtn.val($closeBtn.data("text"));
  457. $openBtn.val($openBtn.data("text"));
  458. } else {
  459. $closeBtn.val($closeBtn.data("origin"));
  460. $openBtn.val($openBtn.data("origin"));
  461. }
  462. });
  463. }());
  464. // issue edit mode
  465. (function () {
  466. $("#issue-edit-btn").on("click", function () {
  467. $('#issue h1.title,#issue .issue-main > .issue-content .content,#issue-edit-btn').toggleHide();
  468. $('#issue-edit-title,#issue-edit-content,.issue-edit-cancel,.issue-edit-save').toggleShow();
  469. });
  470. $('.issue-edit-cancel').on("click", function () {
  471. $('#issue h1.title,#issue .issue-main > .issue-content .content,#issue-edit-btn').toggleShow();
  472. $('#issue-edit-title,#issue-edit-content,.issue-edit-cancel,.issue-edit-save').toggleHide();
  473. })
  474. }());
  475. // issue ajax update
  476. (function () {
  477. $('.issue-edit-save').on("click", function () {
  478. $(this).toggleAjax(function (json) {
  479. if (json.ok) {
  480. $('.issue-head h1.title').text(json.title);
  481. $('.issue-main > .issue-content .content').html(json.content);
  482. $('.issue-edit-cancel').trigger("click");
  483. }
  484. });
  485. });
  486. }());
  487. // issue ajax preview
  488. (function () {
  489. $('[data-ajax-name=issue-preview]').on("click", function () {
  490. var $this = $(this);
  491. $this.toggleAjax(function (resp) {
  492. $($this.data("preview")).html(resp);
  493. })
  494. });
  495. $('.issue-write a[data-toggle]').on("click", function () {
  496. $('.issue-preview-content').html("loading...");
  497. });
  498. }())
  499. }
  500. function initRelease() {
  501. // release new ajax preview
  502. (function () {
  503. $('[data-ajax-name=release-preview]').on("click", function () {
  504. var $this = $(this);
  505. $this.toggleAjax(function (json) {
  506. if (json.ok) {
  507. $($this.data("preview")).html(json.content);
  508. }
  509. })
  510. });
  511. $('.release-write a[data-toggle]').on("click", function () {
  512. $('.release-preview-content').html("loading...");
  513. });
  514. }());
  515. // release new target selection
  516. (function () {
  517. $('#release-new-target-branch-list').on('click', 'a', function () {
  518. $('#tag-target').val($(this).text());
  519. $('#release-new-target-name').text(" " + $(this).text());
  520. });
  521. }());
  522. }
  523. function initRepoSetting() {
  524. // repo member add
  525. $('#repo-collaborator').on('keyup', function () {
  526. var $this = $(this);
  527. if (!$this.val()) {
  528. $this.next().toggleHide();
  529. return;
  530. }
  531. $.ajax({
  532. url: '/api/v1/users/search?q=' + $this.val(),
  533. dataType: "json",
  534. success: function (json) {
  535. if (json.ok && json.data.length) {
  536. var html = '';
  537. $.each(json.data, function (i, item) {
  538. html += '<li><img src="' + item.avatar + '">' + item.username + '</li>';
  539. });
  540. $this.next().toggleShow();
  541. $this.next().find('ul').html(html);
  542. }else{
  543. $this.next().toggleHide();
  544. }
  545. }
  546. });
  547. }).on('focus', function () {
  548. if (!$(this).val()) {
  549. $(this).next().toggleHide();
  550. }
  551. }).next().on("click",'li',function(){
  552. $('#repo-collaborator').val($(this).text());
  553. });
  554. }
  555. (function ($) {
  556. $(function () {
  557. initCore();
  558. var body = $("#body");
  559. if (body.data("page") == "user") {
  560. initUserSetting();
  561. }
  562. if ($('.repo-nav').length) {
  563. initRepository();
  564. }
  565. if ($('#install-card').length) {
  566. initInstall();
  567. }
  568. if ($('#issue').length) {
  569. initIssue();
  570. }
  571. if ($('#release').length) {
  572. initRelease();
  573. }
  574. if ($('#repo-setting-container').length) {
  575. initRepoSetting();
  576. }
  577. });
  578. })(jQuery);