app.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  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, errorCallback) {
  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. console.log("toggleAjax:", method, url, data);
  86. $.ajax({
  87. url: url,
  88. method: method.toUpperCase(),
  89. data: data,
  90. error: errorCallback,
  91. success: function (d) {
  92. if (successCallback) {
  93. successCallback(d);
  94. }
  95. }
  96. })
  97. }
  98. })
  99. }(jQuery));
  100. (function ($) {
  101. Gogits.showTab = function (selector, index) {
  102. if (!index) {
  103. index = 0;
  104. }
  105. $(selector).tab("show");
  106. $(selector).find("li:eq(" + index + ") a").tab("show");
  107. };
  108. Gogits.validateForm = function (selector, options) {
  109. var $form = $(selector);
  110. options = options || {};
  111. options.showErrors = function (map, list) {
  112. var $error = $form.find('.form-error').addClass('hidden');
  113. $('.has-error').removeClass("has-error");
  114. $error.text(list[0].message).show().removeClass("hidden");
  115. $(list[0].element).parents(".form-group").addClass("has-error");
  116. };
  117. $form.validate(options);
  118. };
  119. // ----- init elements
  120. Gogits.initModals = function () {
  121. var modals = $("[data-toggle=modal]");
  122. if (modals.length < 1) {
  123. return;
  124. }
  125. $.each(modals, function (i, item) {
  126. var hide = $(item).data('modal');
  127. $(item).modal(hide ? hide : "hide");
  128. });
  129. };
  130. Gogits.initTooltips = function () {
  131. $("body").tooltip({
  132. selector: "[data-toggle=tooltip]"
  133. //container: "body"
  134. });
  135. };
  136. Gogits.initPopovers = function () {
  137. var hideAllPopovers = function () {
  138. $('[data-toggle=popover]').each(function () {
  139. $(this).popover('hide');
  140. });
  141. };
  142. $(document).on('click', function (e) {
  143. var $e = $(e.target);
  144. if ($e.data('toggle') == 'popover' || $e.parents("[data-toggle=popover], .popover").length > 0) {
  145. return;
  146. }
  147. hideAllPopovers();
  148. });
  149. $("body").popover({
  150. selector: "[data-toggle=popover]"
  151. });
  152. };
  153. Gogits.initTabs = function () {
  154. var $tabs = $('[data-init=tabs]');
  155. $tabs.tab("show");
  156. $tabs.find("li:eq(0) a").tab("show");
  157. };
  158. // fix dropdown inside click
  159. Gogits.initDropDown = function () {
  160. $('.dropdown-menu.no-propagation').on('click', function (e) {
  161. e.stopPropagation();
  162. });
  163. };
  164. // render markdown
  165. Gogits.renderMarkdown = function () {
  166. var $md = $('.markdown');
  167. var $pre = $md.find('pre > code').parent();
  168. $pre.addClass('prettyprint linenums');
  169. prettyPrint();
  170. // Set anchor.
  171. var headers = {};
  172. $md.find('h1, h2, h3, h4, h5, h6').each(function () {
  173. var node = $(this);
  174. var val = encodeURIComponent(node.text().toLowerCase().replace(/[^\w\- ]/g, '').replace(/[ ]/g, '-'));
  175. var name = val;
  176. if (headers[val] > 0) {
  177. name = val + '-' + headers[val];
  178. }
  179. if (headers[val] == undefined) {
  180. headers[val] = 1;
  181. } else {
  182. headers[val] += 1;
  183. }
  184. node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>');
  185. node.append('<a class="anchor" href="#' + name + '"><span class="octicon octicon-link"></span></a>');
  186. });
  187. };
  188. // render code view
  189. Gogits.renderCodeView = function () {
  190. function selectRange($list, $select, $from) {
  191. $list.removeClass('active');
  192. if ($from) {
  193. var a = parseInt($select.attr('rel').substr(1));
  194. var b = parseInt($from.attr('rel').substr(1));
  195. var c;
  196. if (a != b) {
  197. if (a > b) {
  198. c = a;
  199. a = b;
  200. b = c;
  201. }
  202. var classes = [];
  203. for (i = a; i <= b; i++) {
  204. classes.push('.L' + i);
  205. }
  206. $list.filter(classes.join(',')).addClass('active');
  207. $.changeHash('#L' + a + '-' + 'L' + b);
  208. return
  209. }
  210. }
  211. $select.addClass('active');
  212. $.changeHash('#' + $select.attr('rel'));
  213. }
  214. $(document).on('click', '.lines-num span', function (e) {
  215. var $select = $(this);
  216. var $list = $select.parent().siblings('.lines-code').find('ol.linenums > li');
  217. selectRange($list, $list.filter('[rel=' + $select.attr('rel') + ']'), (e.shiftKey ? $list.filter('.active').eq(0) : null));
  218. $.deSelect();
  219. });
  220. $('.code-view .lines-code > pre').each(function () {
  221. var $pre = $(this);
  222. var $lineCode = $pre.parent();
  223. var $lineNums = $lineCode.siblings('.lines-num');
  224. if ($lineNums.length > 0) {
  225. var nums = $pre.find('ol.linenums > li').length;
  226. for (var i = 1; i <= nums; i++) {
  227. $lineNums.append('<span id="L' + i + '" rel="L' + i + '">' + i + '</span>');
  228. }
  229. }
  230. });
  231. $(window).on('hashchange', function (e) {
  232. var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/);
  233. var $list = $('.code-view ol.linenums > li');
  234. if (m) {
  235. var $first = $list.filter('.' + m[1]);
  236. selectRange($list, $first, $list.filter('.' + m[2]));
  237. $("html, body").scrollTop($first.offset().top - 200);
  238. return;
  239. }
  240. m = window.location.hash.match(/^#(L\d+)$/);
  241. if (m) {
  242. var $first = $list.filter('.' + m[1]);
  243. selectRange($list, $first);
  244. $("html, body").scrollTop($first.offset().top - 200);
  245. }
  246. }).trigger('hashchange');
  247. };
  248. // copy utils
  249. Gogits.bindCopy = function (selector) {
  250. if ($(selector).hasClass('js-copy-bind')) {
  251. return;
  252. }
  253. $(selector).zclip({
  254. path: "/js/ZeroClipboard.swf",
  255. copy: function () {
  256. var t = $(this).data("copy-val");
  257. var to = $($(this).data("copy-from"));
  258. var str = "";
  259. if (t == "txt") {
  260. str = to.text();
  261. }
  262. if (t == 'val') {
  263. str = to.val();
  264. }
  265. if (t == 'html') {
  266. str = to.html();
  267. }
  268. return str;
  269. },
  270. afterCopy: function () {
  271. var $this = $(this);
  272. $this.tooltip('hide')
  273. .attr('data-original-title', 'Copied OK');
  274. setTimeout(function () {
  275. $this.tooltip("show");
  276. }, 200);
  277. setTimeout(function () {
  278. $this.tooltip('hide')
  279. .attr('data-original-title', 'Copy to Clipboard');
  280. }, 3000);
  281. }
  282. }).addClass("js-copy-bind");
  283. }
  284. // api working
  285. Gogits.getUsers = function (val, $target) {
  286. var notEmpty = function (str) {
  287. return str && str.length > 0;
  288. }
  289. $.ajax({
  290. url: '/api/v1/users/search?q=' + val,
  291. dataType: "json",
  292. success: function (json) {
  293. if (json.ok && json.data.length) {
  294. var html = '';
  295. $.each(json.data, function (i, item) {
  296. html += '<li><img src="' + item.avatar + '">' + item.username;
  297. if (notEmpty(item.full_name)) {
  298. html += ' (' + item.full_name + ')';
  299. }
  300. html += '</li>';
  301. });
  302. $target.toggleShow();
  303. $target.find('ul').html(html);
  304. } else {
  305. $target.toggleHide();
  306. }
  307. }
  308. });
  309. }
  310. })(jQuery);
  311. // ajax utils
  312. (function ($) {
  313. Gogits.ajaxDelete = function (url, data, success) {
  314. data = data || {};
  315. data._method = "DELETE";
  316. $.ajax({
  317. url: url,
  318. data: data,
  319. method: "POST",
  320. dataType: "json",
  321. success: function (json) {
  322. if (success) {
  323. success(json);
  324. }
  325. }
  326. })
  327. }
  328. })(jQuery);
  329. function initCore() {
  330. Gogits.initTooltips();
  331. Gogits.initPopovers();
  332. Gogits.initTabs();
  333. Gogits.initModals();
  334. Gogits.initDropDown();
  335. Gogits.renderMarkdown();
  336. Gogits.renderCodeView();
  337. }
  338. function initUserSetting() {
  339. // ssh confirmation
  340. $('#ssh-keys .delete').confirmation({
  341. singleton: true,
  342. onConfirm: function (e, $this) {
  343. Gogits.ajaxDelete("", {"id": $this.data("del")}, function (json) {
  344. if (json.ok) {
  345. window.location.reload();
  346. } else {
  347. alert(json.err);
  348. }
  349. });
  350. }
  351. });
  352. // profile form
  353. (function () {
  354. $('#user-setting-username').on("keyup", function () {
  355. var $this = $(this);
  356. if ($this.val() != $this.attr('title')) {
  357. $this.next('.help-block').toggleShow();
  358. } else {
  359. $this.next('.help-block').toggleHide();
  360. }
  361. });
  362. }())
  363. }
  364. function initRepository() {
  365. // clone group button script
  366. (function () {
  367. var $clone = $('.clone-group-btn');
  368. if ($clone.length) {
  369. var $url = $('.clone-group-url');
  370. $clone.find('button[data-link]').on("click", function (e) {
  371. var $this = $(this);
  372. if (!$this.hasClass('btn-primary')) {
  373. $clone.find('.input-group-btn .btn-primary').removeClass('btn-primary').addClass("btn-default");
  374. $(this).addClass('btn-primary').removeClass('btn-default');
  375. $url.val($this.data("link"));
  376. $clone.find('span.clone-url').text($this.data('link'));
  377. }
  378. }).eq(0).trigger("click");
  379. $("#repo-clone").on("shown.bs.dropdown", function () {
  380. Gogits.bindCopy("[data-init=copy]");
  381. });
  382. Gogits.bindCopy("[data-init=copy]:visible");
  383. }
  384. })();
  385. // watching script
  386. (function () {
  387. var $watch = $('#repo-watching'),
  388. watchLink = $watch.attr("data-watch"),
  389. // Use $.attr() to work around jQuery not finding $.data("unwatch") in Firefox,
  390. // which has a method "unwatch" on `Object` that gets returned instead.
  391. unwatchLink = $watch.attr("data-unwatch");
  392. $watch.on('click', '.to-watch', function () {
  393. if ($watch.hasClass("watching")) {
  394. return false;
  395. }
  396. $.get(watchLink, function (json) {
  397. if (json.ok) {
  398. $watch.find('.text-primary').removeClass('text-primary');
  399. $watch.find('.to-watch h4').addClass('text-primary');
  400. $watch.find('.fa-eye-slash').removeClass('fa-eye-slash').addClass('fa-eye');
  401. $watch.removeClass("no-watching").addClass("watching");
  402. }
  403. });
  404. return false;
  405. }).on('click', '.to-unwatch', function () {
  406. if ($watch.hasClass("no-watching")) {
  407. return false;
  408. }
  409. $.get(unwatchLink, function (json) {
  410. if (json.ok) {
  411. $watch.find('.text-primary').removeClass('text-primary');
  412. $watch.find('.to-unwatch h4').addClass('text-primary');
  413. $watch.find('.fa-eye').removeClass('fa-eye').addClass('fa-eye-slash');
  414. $watch.removeClass("watching").addClass("no-watching");
  415. }
  416. });
  417. return false;
  418. });
  419. })();
  420. // repo diff counter
  421. (function () {
  422. var $counter = $('.diff-counter');
  423. if ($counter.length < 1) {
  424. return;
  425. }
  426. $counter.each(function (i, item) {
  427. var $item = $(item);
  428. var addLine = $item.find('span[data-line].add').data("line");
  429. var delLine = $item.find('span[data-line].del').data("line");
  430. var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100;
  431. $item.find(".bar .add").css("width", addPercent + "%");
  432. });
  433. }());
  434. // repo setting form
  435. (function () {
  436. $('#repo-setting-name').on("keyup", function () {
  437. var $this = $(this);
  438. if ($this.val() != $this.attr('title')) {
  439. $this.next('.help-block').toggleShow();
  440. } else {
  441. $this.next('.help-block').toggleHide();
  442. }
  443. });
  444. }())
  445. }
  446. function initInstall() {
  447. // database type change
  448. (function () {
  449. var mysql_default = '127.0.0.1:3306';
  450. var postgres_default = '127.0.0.1:5432';
  451. $('#install-database').on("change", function () {
  452. var val = $(this).val();
  453. if (val != "SQLite3") {
  454. $('.server-sql').show();
  455. $('.sqlite-setting').addClass("hide");
  456. if (val == "PostgreSQL") {
  457. $('.pgsql-setting').removeClass("hide");
  458. // Change the host value to the Postgres default, but only
  459. // if the user hasn't already changed it from the MySQL
  460. // default.
  461. if ($('#database-host').val() == mysql_default) {
  462. $('#database-host').val(postgres_default);
  463. }
  464. } else if (val == 'MySQL') {
  465. $('.pgsql-setting').addClass("hide");
  466. if ($('#database-host').val() == postgres_default) {
  467. $('#database-host').val(mysql_default);
  468. }
  469. } else {
  470. $('.pgsql-setting').addClass("hide");
  471. }
  472. } else {
  473. $('.server-sql').hide();
  474. $('.sqlite-setting').removeClass("hide");
  475. }
  476. });
  477. }());
  478. }
  479. function initIssue() {
  480. // close button
  481. (function () {
  482. var $closeBtn = $('#issue-close-btn');
  483. var $openBtn = $('#issue-open-btn');
  484. $('#issue-reply-content').on("keyup", function () {
  485. if ($(this).val().length) {
  486. $closeBtn.val($closeBtn.data("text"));
  487. $openBtn.val($openBtn.data("text"));
  488. } else {
  489. $closeBtn.val($closeBtn.data("origin"));
  490. $openBtn.val($openBtn.data("origin"));
  491. }
  492. });
  493. }());
  494. // store unsend text in session storage.
  495. (function() {
  496. var $textArea = $("#issue-content,#issue-reply-content");
  497. var current = "";
  498. if ($textArea == null || !('sessionStorage' in window)) {
  499. return;
  500. }
  501. var path = location.pathname.split("/");
  502. var key = "issue-" + path[1] + "-" + path[2] + "-";
  503. if (/\/issues\/\d+$/.test(location.pathname)) {
  504. key = key + path[4];
  505. } else {
  506. key = key + "new";
  507. }
  508. if ($textArea.val() !== undefined && $textArea.val() !== "") {
  509. sessionStorage.setItem(key, $textArea.val());
  510. } else {
  511. $textArea.val(sessionStorage.getItem(key) || "");
  512. if ($textArea.attr("id") == "issue-reply-content") {
  513. var $closeBtn = $('#issue-close-btn');
  514. var $openBtn = $('#issue-open-btn');
  515. if ($textArea.val().length) {
  516. $closeBtn.val($closeBtn.data("text"));
  517. $openBtn.val($openBtn.data("text"));
  518. } else {
  519. $closeBtn.val($closeBtn.data("origin"));
  520. $openBtn.val($openBtn.data("origin"));
  521. }
  522. }
  523. }
  524. $textArea.on("keyup", function() {
  525. if ($textArea.val() !== current) {
  526. sessionStorage.setItem(key, current = $textArea.val());
  527. }
  528. });
  529. }());
  530. // Preview for images.
  531. (function() {
  532. var $hoverElement = $("<div></div>");
  533. var $hoverImage = $("<img />");
  534. $hoverElement.addClass("attachment-preview");
  535. $hoverElement.hide();
  536. $hoverImage.addClass("attachment-preview-img");
  537. $hoverElement.append($hoverImage);
  538. $(document.body).append($hoverElement);
  539. var over = function() {
  540. var $this = $(this);
  541. if ((/\.(png|jpg|jpeg|gif)$/i).test($this.text()) == false) {
  542. return;
  543. }
  544. if ($hoverImage.attr("src") != $this.attr("href")) {
  545. $hoverImage.attr("src", $this.attr("href"));
  546. $hoverImage.load(function() {
  547. var height = this.height;
  548. var width = this.width;
  549. if (height > 300) {
  550. var factor = 300 / height;
  551. height = factor * height;
  552. width = factor * width;
  553. }
  554. $hoverImage.css({"height": height, "width": width});
  555. var offset = $this.offset();
  556. var left = offset.left, top = offset.top + $this.height() + 5;
  557. $hoverElement.css({"top": top + "px", "left": left + "px"});
  558. $hoverElement.css({"height": height + 16, "width": width + 16});
  559. $hoverElement.show();
  560. });
  561. } else {
  562. $hoverElement.show();
  563. }
  564. };
  565. var out = function() {
  566. $hoverElement.hide();
  567. };
  568. $(".issue-main .attachments .attachment").hover(over, out);
  569. }());
  570. // Upload.
  571. (function() {
  572. var $attachedList = $("#attached-list");
  573. var $addButton = $("#attachments-button");
  574. var files = [];
  575. var fileInput = document.getElementById("attachments-input");
  576. if (fileInput === null) {
  577. return;
  578. }
  579. $attachedList.on("click", "span.attachment-remove", function(event) {
  580. var $parent = $(this).parent();
  581. files.splice($parent.data("index"), 1);
  582. $parent.remove();
  583. });
  584. var clickedButton;
  585. $('input[type="submit"],input[type="button"],button.btn-success', fileInput.form).on('click', function() {
  586. clickedButton = this;
  587. var $button = $(this);
  588. $button.removeClass("btn-success btn-default");
  589. $button.addClass("btn-warning");
  590. $button.html("Submitting&hellip;");
  591. });
  592. fileInput.form.addEventListener("submit", function(event) {
  593. event.stopImmediatePropagation();
  594. event.preventDefault();
  595. //var data = new FormData(this);
  596. // Internet Explorer ... -_-
  597. var data = new FormData();
  598. $.each($("[name]", this), function(i, e) {
  599. if (e.name == "attachments" || e.type == "submit") {
  600. return;
  601. }
  602. data.append(e.name, $(e).val());
  603. });
  604. data.append(clickedButton.name, $(clickedButton).val());
  605. files.forEach(function(file) {
  606. data.append("attachments", file);
  607. });
  608. var xhr = new XMLHttpRequest();
  609. xhr.addEventListener("error", function() {
  610. console.log("Issue submit request failed. xhr.status: " + xhr.status);
  611. });
  612. xhr.addEventListener("load", function() {
  613. var response = xhr.response;
  614. if (typeof response == "string") {
  615. try {
  616. response = JSON.parse(response);
  617. } catch (err) {
  618. response = { ok: false, error: "Could not parse JSON" };
  619. }
  620. }
  621. if (response.ok === false) {
  622. $("#submit-error").text(response.error);
  623. $("#submit-error").show();
  624. var $button = $(clickedButton);
  625. $button.removeClass("btn-warning");
  626. $button.addClass("btn-danger");
  627. $button.text("An error occurred!");
  628. return;
  629. }
  630. if (!('sessionStorage' in window)) {
  631. return;
  632. }
  633. var path = location.pathname.split("/");
  634. var key = "issue-" + path[1] + "-" + path[2] + "-";
  635. if (/\/issues\/\d+$/.test(location.pathname)) {
  636. key = key + path[4];
  637. } else {
  638. key = key + "new";
  639. }
  640. sessionStorage.removeItem(key);
  641. window.location.href = response.data;
  642. });
  643. xhr.open("POST", this.action, true);
  644. xhr.send(data);
  645. return false;
  646. });
  647. fileInput.addEventListener("change", function() {
  648. for (var index = 0; index < fileInput.files.length; index++) {
  649. var file = fileInput.files[index];
  650. if (files.indexOf(file) > -1) {
  651. continue;
  652. }
  653. var $span = $("<span></span>");
  654. $span.addClass("label");
  655. $span.addClass("label-default");
  656. $span.data("index", files.length);
  657. $span.append(file.name);
  658. $span.append(" <span class=\"attachment-remove fa fa-times-circle\"></span>");
  659. $attachedList.append($span);
  660. files.push(file);
  661. }
  662. this.value = "";
  663. });
  664. $addButton.on("click", function(evt) {
  665. fileInput.click();
  666. evt.preventDefault();
  667. });
  668. }());
  669. // issue edit mode
  670. (function () {
  671. $("#issue-edit-btn").on("click", function () {
  672. $('#issue h1.title,#issue .issue-main > .issue-content .content,#issue-edit-btn').toggleHide();
  673. $('#issue-edit-title,.issue-edit-content,.issue-edit-cancel,.issue-edit-save').toggleShow();
  674. });
  675. $('.issue-edit-cancel').on("click", function () {
  676. $('#issue h1.title,#issue .issue-main > .issue-content .content,#issue-edit-btn').toggleShow();
  677. $('#issue-edit-title,.issue-edit-content,.issue-edit-cancel,.issue-edit-save').toggleHide();
  678. });
  679. }());
  680. // issue ajax update
  681. (function () {
  682. var $cnt = $('#issue-edit-content');
  683. $('.issue-edit-save').on("click", function () {
  684. $cnt.attr('data-ajax-rel', 'issue-edit-save');
  685. $(this).toggleAjax(function (json) {
  686. if (json.ok) {
  687. $('.issue-head h1.title').text(json.title);
  688. $('.issue-main > .issue-content .content').html(json.content);
  689. $('.issue-edit-cancel').trigger("click");
  690. }
  691. });
  692. setTimeout(function () {
  693. $cnt.attr('data-ajax-rel', 'issue-edit-preview');
  694. }, 200)
  695. });
  696. }());
  697. // issue ajax preview
  698. (function () {
  699. $('[data-ajax-name=issue-preview],[data-ajax-name=issue-edit-preview]').on("click", function () {
  700. var $this = $(this);
  701. $this.toggleAjax(function (resp) {
  702. $($this.data("preview")).html(resp);
  703. }, function () {
  704. $($this.data("preview")).html("no content");
  705. })
  706. });
  707. $('.issue-write a[data-toggle]').on("click", function () {
  708. var selector = $(this).parent().next(".issue-preview").find('a').data('preview');
  709. $(selector).html("loading...");
  710. });
  711. }());
  712. // assignee
  713. var is_issue_bar = $('.issue-bar').length > 0;
  714. var $a = $('.assignee');
  715. if ($a.data("assigned") > 0) {
  716. $('.clear-assignee').toggleShow();
  717. }
  718. $('.assignee', '#issue').on('click', 'li', function () {
  719. var uid = $(this).data("uid");
  720. if (is_issue_bar) {
  721. var assignee = $a.data("assigned");
  722. if (uid != assignee) {
  723. var text = $(this).text();
  724. var img = $("img", this).attr("src");
  725. $.post($a.data("ajax"), {
  726. issue: $('#issue').data("id"),
  727. assigneeid: uid
  728. }, function (json) {
  729. if (json.ok) {
  730. //window.location.reload();
  731. $a.data("assigned", uid);
  732. if (uid > 0) {
  733. $('.clear-assignee').toggleShow();
  734. $(".assignee > p").html('<img src="' + img + '"><strong>' + text + '</strong>');
  735. } else {
  736. $('.clear-assignee').toggleHide();
  737. $(".assignee > p").text("No one assigned");
  738. }
  739. }
  740. })
  741. }
  742. return;
  743. }
  744. $('#assignee').val(uid);
  745. if (uid > 0) {
  746. $('.clear-assignee').toggleShow();
  747. $('#assigned').text($(this).find("strong").text())
  748. } else {
  749. $('.clear-assignee').toggleHide();
  750. $('#assigned').text($('#assigned').data("no-assigned"));
  751. }
  752. });
  753. // milestone
  754. $('#issue .dropdown-menu a[data-toggle="tab"]').on("click", function (e) {
  755. e.stopPropagation();
  756. $(this).tab('show');
  757. return false;
  758. });
  759. var $m = $('.milestone');
  760. if ($m.data("milestone") > 0) {
  761. $('.clear-milestone').toggleShow();
  762. }
  763. $('.milestone', '#issue').on('click', 'li.milestone-item', function () {
  764. var id = $(this).data("id");
  765. if (is_issue_bar) {
  766. var m = $m.data("milestone");
  767. if (id != m) {
  768. var text = $(this).text();
  769. $.post($m.data("ajax"), {
  770. issue: $('#issue').data("id"),
  771. milestoneid: id
  772. }, function (json) {
  773. if (json.ok) {
  774. //window.location.reload();
  775. $m.data("milestone", id);
  776. if (id > 0) {
  777. $('.clear-milestone').toggleShow();
  778. $(".milestone > .name").html('<a href="' + location.pathname + '?milestone=' + id + '"><strong>' + text + '</strong></a>');
  779. } else {
  780. $('.clear-milestone').toggleHide();
  781. $(".milestone > .name").text("No milestone");
  782. }
  783. }
  784. });
  785. }
  786. return;
  787. }
  788. $('#milestone-id').val(id);
  789. if (id > 0) {
  790. $('.clear-milestone').toggleShow();
  791. $('#milestone').text($(this).find("strong").text())
  792. } else {
  793. $('.clear-milestone').toggleHide();
  794. $('#milestone').text($('#milestone').data("no-milestone"));
  795. }
  796. });
  797. // labels
  798. var removeLabels = [];
  799. $('#label-manage-btn').on("click", function () {
  800. var $list = $('#label-list');
  801. if ($list.hasClass("managing")) {
  802. var ids = [];
  803. $list.find('li').each(function (i, item) {
  804. var id = $(item).data("id");
  805. if (id > 0) {
  806. ids.push(id);
  807. }
  808. });
  809. $.post($list.data("ajax"), {"ids": ids.join(","), "remove": removeLabels.join(",")}, function (json) {
  810. if (json.ok) {
  811. window.location.reload();
  812. }
  813. })
  814. } else {
  815. $list.addClass("managing");
  816. $list.find(".count").hide();
  817. $list.find(".del").show();
  818. $(this).text("Save Labels");
  819. $list.on('click', 'li.label-item', function () {
  820. var $this = $(this);
  821. $this.after($('.label-change-li').detach().show());
  822. $('#label-name-change-ipt').val($this.find('.name').text());
  823. var color = $this.find('.color').data("color");
  824. $('.label-change-color-picker').colorpicker("setValue", color);
  825. $('#label-color-change-ipt,#label-color-change-ipt2').val(color);
  826. $('#label-change-id-ipt').val($this.data("id"));
  827. return false;
  828. });
  829. }
  830. });
  831. var colorRegex = new RegExp("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$");
  832. $('#label-color-ipt2').on('keyup', function () {
  833. var val = $(this).val();
  834. if (val.length > 7) {
  835. $(this).val(val.substr(0, 7));
  836. }
  837. if (colorRegex.test(val)) {
  838. $('.label-color-picker').colorpicker("setValue", val);
  839. }
  840. return true;
  841. });
  842. $('#label-color-change-ipt2').on('keyup', function () {
  843. var val = $(this).val();
  844. console.log(val);
  845. if (val.length > 7) {
  846. $(this).val(val.substr(0, 7));
  847. }
  848. if (colorRegex.test(val)) {
  849. $('.label-change-color-picker').colorpicker("setValue", val);
  850. }
  851. return true;
  852. });
  853. $("#label-list").on('click', '.del', function () {
  854. var $p = $(this).parent();
  855. removeLabels.push($p.data('id'));
  856. $p.remove();
  857. return false;
  858. });
  859. $('.label-selected').each(function (i, item) {
  860. var $item = $(item);
  861. var color = $item.find('.color').data('color');
  862. $item.css('background-color', color);
  863. });
  864. $('.issue-bar .labels .dropdown-menu').on('click', 'li', function (e) {
  865. var $labels = $('.issue-bar .labels');
  866. var url = $labels.data("ajax");
  867. var id = $(this).data('id');
  868. var check = $(this).hasClass("checked");
  869. var item = this;
  870. $.post(url, {id: id, action: check ? 'detach' : "attach", issue: $('#issue').data('id')}, function (json) {
  871. if (json.ok) {
  872. if (check) {
  873. $("span.check.pull-left", item).remove();
  874. $(item).removeClass("checked");
  875. $(item).addClass("no-checked");
  876. $("#label-" + id, $labels).remove();
  877. if ($labels.children(".label-item").length == 0) {
  878. $labels.append("<p>None yet</p>");
  879. }
  880. } else {
  881. $(item).prepend('<span class="check pull-left"><i class="fa fa-check"></i></span>');
  882. $(item).removeClass("no-checked");
  883. $(item).addClass("checked");
  884. $("p:not([class])", $labels).remove();
  885. var $l = $("<p></p>");
  886. var c = $("span.color", item).css("background-color");
  887. $l.attr("id", "label-" + id);
  888. $l.attr("class", "label-item label-white");
  889. $l.css("background-color", c);
  890. $l.append("<strong>" + $(item).text() + "</strong>");
  891. $labels.append($l);
  892. }
  893. }
  894. });
  895. e.stopPropagation();
  896. return false;
  897. })
  898. }
  899. function initRelease() {
  900. // release new ajax preview
  901. (function () {
  902. $('[data-ajax-name=release-preview]').on("click", function () {
  903. var $this = $(this);
  904. $this.toggleAjax(function (resp) {
  905. $($this.data("preview")).html(resp);
  906. }, function () {
  907. $($this.data("preview")).html("no content");
  908. })
  909. });
  910. $('.release-write a[data-toggle]').on("click", function () {
  911. $('.release-preview-content').html("loading...");
  912. });
  913. }());
  914. // release new target selection
  915. (function () {
  916. $('#release-new-target-branch-list').on('click', 'a', function () {
  917. $('#tag-target').val($(this).text());
  918. $('#release-new-target-name').text(" " + $(this).text());
  919. });
  920. }());
  921. }
  922. function initRepoSetting() {
  923. // repo member add
  924. $('#repo-collaborator').on('keyup', function () {
  925. var $this = $(this);
  926. if (!$this.val()) {
  927. $this.next().toggleHide();
  928. return;
  929. }
  930. Gogits.getUsers($this.val(), $this.next());
  931. }).on('focus', function () {
  932. if (!$(this).val()) {
  933. $(this).next().toggleHide();
  934. }
  935. }).next().on("click", 'li', function () {
  936. $('#repo-collaborator').val($(this).text());
  937. });
  938. }
  939. function initRepoCreating() {
  940. // owner switch menu click
  941. (function () {
  942. $('#repo-owner-switch .dropdown-menu').on("click", "li", function () {
  943. var uid = $(this).data('uid');
  944. // set to input
  945. $('#repo-owner-id').val(uid);
  946. // set checked class
  947. if (!$(this).hasClass("checked")) {
  948. $(this).parent().find(".checked").removeClass("checked");
  949. $(this).addClass("checked");
  950. }
  951. // set button group to show clicked owner
  952. $('#repo-owner-avatar').attr("src", $(this).find('img').attr("src"));
  953. $('#repo-owner-name').text($(this).text().trim());
  954. console.log("set repo owner to uid :", uid, $(this).text().trim());
  955. });
  956. }());
  957. console.log("init repo-creating scripts");
  958. }
  959. function initOrganization() {
  960. (function(){
  961. $('#org-team-add-user').on('keyup', function () {
  962. var $this = $(this);
  963. if (!$this.val()) {
  964. $this.next().toggleHide();
  965. return;
  966. }
  967. Gogits.getUsers($this.val(), $this.next());
  968. }).on('focus', function () {
  969. if (!$(this).val()) {
  970. $(this).next().toggleHide();
  971. }
  972. }).next().on("click", 'li', function () {
  973. $('#org-team-add-user').val($(this).text());
  974. $('#org-team-add-user-form').submit();
  975. }).toggleHide();
  976. console.log("init script : add user to team");
  977. }());
  978. (function(){
  979. $('#org-team-add-repo').next().toggleHide();
  980. console.log("init script : add repository to team");
  981. }());
  982. console.log("init script : organization done");
  983. }
  984. function initTimeSwitch() {
  985. $(".time-since[title]").on("click", function() {
  986. var $this = $(this);
  987. var title = $this.attr("title");
  988. var text = $this.text();
  989. $this.text(title);
  990. $this.attr("title", text);
  991. });
  992. }
  993. (function ($) {
  994. $(function () {
  995. initCore();
  996. var body = $("#body");
  997. if (body.data("page") == "user") {
  998. initUserSetting();
  999. }
  1000. if ($('.repo-nav').length) {
  1001. initRepository();
  1002. }
  1003. if ($('#install-card').length) {
  1004. initInstall();
  1005. }
  1006. if ($('#issue').length) {
  1007. initIssue();
  1008. }
  1009. if ($('#release').length) {
  1010. initRelease();
  1011. }
  1012. if ($('#repo-setting-container').length) {
  1013. initRepoSetting();
  1014. }
  1015. if ($('#repo-create').length) {
  1016. initRepoCreating();
  1017. }
  1018. if ($('#body-nav').hasClass("org-nav")) {
  1019. initOrganization();
  1020. }
  1021. initTimeSwitch();
  1022. });
  1023. })(jQuery);
  1024. String.prototype.endsWith = function (suffix) {
  1025. return this.indexOf(suffix, this.length - suffix.length) !== -1;
  1026. };