暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. /// <reference path="./card.ts" />
  2. /// <reference path="./colors.ts" />
  3. /// <reference path="./icons.ts" />
  4. /// <reference path="./example_data.ts" />
  5. /// <reference path="./jquery.d.ts" />
  6. /// <reference path="./ace.d.ts" />
  7. /// <reference path="./shortcut.d.ts" />
  8. module RpgCardsUI {
  9. var deck: RpgCards.CardDeck = null;
  10. var options: RpgCards.Options = null;
  11. var cardGenerator: RpgCards.CardHtmlGenerator = null;
  12. var pageGenerator: RpgCards.PageHtmlGenerator = null;
  13. var editor: AceAjax.Editor;
  14. var update_in_progress: boolean = false;
  15. // ============================================================================
  16. // Seleted card
  17. // ============================================================================
  18. function selected_card_index(): number {
  19. return parseInt($("#selected-card").val(), 10);
  20. }
  21. function selected_card(): RpgCards.Card {
  22. var index = selected_card_index();
  23. if (deck.cards.length > index) {
  24. return deck.cards[index];
  25. } else {
  26. return null;
  27. }
  28. }
  29. function select_card_by_index(index: number) {
  30. var size = deck.cards.length;
  31. if (size === 0) {
  32. $("#selected-card").val("");
  33. update_selected_card();
  34. } else {
  35. index = Math.min(size - 1, index);
  36. index = Math.max(0, index);
  37. if (index != selected_card_index()) {
  38. $("#selected-card").val("" + index);
  39. update_selected_card();
  40. }
  41. }
  42. }
  43. function select_first_card() {
  44. select_card_by_index(0);
  45. }
  46. function select_last_card() {
  47. select_card_by_index(deck.cards.length - 1);
  48. }
  49. function select_next_card() {
  50. select_card_by_index(selected_card_index() + 1);
  51. }
  52. function select_prev_card() {
  53. select_card_by_index(selected_card_index() - 1);
  54. }
  55. function select_card_by_card(card: RpgCards.Card) {
  56. var index = deck.cards.indexOf(card);
  57. select_card_by_index(index);
  58. }
  59. // ============================================================================
  60. // Rendering
  61. // ============================================================================
  62. function render_selected_card() {
  63. if (update_in_progress) {
  64. return;
  65. }
  66. var card = selected_card();
  67. $('#preview-container').empty();
  68. if (card) {
  69. var front = cardGenerator.card_front(card, options, " ");
  70. var back = cardGenerator.card_back(card, options, " ");
  71. $('#preview-container').html(front + "\n" + back);
  72. }
  73. }
  74. function update_selected_card() {
  75. update_in_progress = true;
  76. var card = selected_card();
  77. if (card) {
  78. $("#card-title").val(card.title);
  79. $("#card-title-size").val(card.title_size);
  80. $("#card-title-icon-text").val(card.title_icon_text);
  81. $("#card-count").val(""+card.count);
  82. $("#card-icon").val(card.icon);
  83. $("#card-icon-back").val(card.icon_back);
  84. //$("#card-contents").val(card.contents.join("\n"));
  85. editor.setValue(card.contents.join("\n"), -1);
  86. $("#card-tags").val(card.tags.join(", "));
  87. $("#card-color").val(card.color).change();
  88. } else {
  89. $("#card-title").val("");
  90. $("#card-title-size").val("");
  91. $("#card-title-icon-text").val("");
  92. $("#card-count").val("1");
  93. $("#card-icon").val("");
  94. $("#card-icon-back").val("");
  95. //$("#card-contents").val("");
  96. editor.setValue("");
  97. $("#card-tags").val("");
  98. $("#card-color").val("").change();
  99. }
  100. update_in_progress = false;
  101. render_selected_card();
  102. }
  103. function update_card_list() {
  104. deck.commit();
  105. $("#total_card_count").text("This deck contains " + deck.cards.length + " unique cards.");
  106. $('#selected-card').empty();
  107. for (var i = 0; i < deck.cards.length; ++i) {
  108. var card = deck.cards[i];
  109. $('#selected-card')
  110. .append($("<option></option>")
  111. .attr("value", i)
  112. .text(card.title));
  113. }
  114. update_selected_card();
  115. }
  116. // ============================================================================
  117. // Color picker
  118. // ============================================================================
  119. function setup_color_selector() {
  120. // Insert colors
  121. $.each(card_colors, function (name, val) {
  122. $(".colorselector-data")
  123. .append($("<option></option>")
  124. .attr("value", name)
  125. .attr("data-color", val)
  126. .text(name));
  127. });
  128. // Callbacks for when the user picks a color
  129. (<any>$('#default_color_selector')).colorselector({
  130. callback: function (value, color, title) {
  131. $("#default-color").val(title);
  132. set_default_color(title);
  133. }
  134. });
  135. (<any>$('#card_color_selector')).colorselector({
  136. callback: function (value, color, title) {
  137. $("#card-color").val(title);
  138. set_card_color(value);
  139. }
  140. });
  141. (<any>$('#foreground_color_selector')).colorselector({
  142. callback: function (value, color, title) {
  143. $("#foreground-color").val(title);
  144. set_foreground_color(value);
  145. }
  146. });
  147. (<any>$('#background_color_selector')).colorselector({
  148. callback: function (value, color, title) {
  149. $("#background-color").val(title);
  150. set_background_color(value);
  151. }
  152. });
  153. // Styling
  154. $(".dropdown-colorselector").addClass("input-group-addon color-input-addon");
  155. }
  156. function set_card_color(value) {
  157. var card = selected_card();
  158. if (card) {
  159. card.color = value;
  160. render_selected_card();
  161. }
  162. }
  163. function set_default_color(color) {
  164. options.default_color = color;
  165. render_selected_card();
  166. }
  167. function set_foreground_color(color) {
  168. options.foreground_color = color;
  169. }
  170. function set_background_color(color) {
  171. options.background_color = color;
  172. }
  173. function update_card_color_selector(color, input, selector) {
  174. if ($(selector + " option[value='" + color + "']").length > 0) {
  175. // Update the color selector to the entered value
  176. (<any>$(selector)).colorselector("setValue", color);
  177. } else {
  178. // Unknown color - select a neutral color and reset the text value
  179. (<any>$(selector)).colorselector("setValue", "");
  180. input.val(color);
  181. }
  182. }
  183. // ============================================================================
  184. // Card values
  185. // ============================================================================
  186. function on_change_card_title() {
  187. var title = $("#card-title").val();
  188. var card = selected_card();
  189. if (card) {
  190. card.title = title;
  191. $("#selected-card option:selected").text(title);
  192. render_selected_card();
  193. }
  194. }
  195. function on_change_card_color() {
  196. var input = $(this);
  197. var color = input.val();
  198. update_card_color_selector(color, input, "#card_color_selector");
  199. set_card_color(color);
  200. }
  201. function on_change_card_property() {
  202. var property = $(this).attr("data-property");
  203. var value = $(this).val();
  204. var card = selected_card();
  205. if (card) {
  206. card[property] = value;
  207. render_selected_card();
  208. }
  209. }
  210. function on_change_card_contents() {
  211. var value = editor.getValue();
  212. var card = selected_card();
  213. if (card) {
  214. card.contents = value.split("\n");
  215. render_selected_card();
  216. }
  217. }
  218. function on_change_card_tags() {
  219. var value = $(this).val();
  220. var card = selected_card();
  221. if (card) {
  222. if (value.trim().length == 0) {
  223. card.tags = [];
  224. } else {
  225. card.tags = value.split(",").map(function (val) {
  226. return val.trim().toLowerCase();
  227. });
  228. }
  229. render_selected_card();
  230. }
  231. }
  232. // ============================================================================
  233. // Global default values
  234. // ============================================================================
  235. function on_change_option() {
  236. var property = $(this).attr("data-option");
  237. var value = $(this).val();
  238. options[property] = value;
  239. render_selected_card();
  240. }
  241. function on_change_default_color() {
  242. var input = $(this);
  243. var color = input.val();
  244. update_card_color_selector(color, input, "#default_color_selector");
  245. set_default_color(color);
  246. }
  247. function on_change_default_icon() {
  248. var value = $(this).val();
  249. options.default_icon = value;
  250. render_selected_card();
  251. }
  252. function on_change_default_title_size() {
  253. options.default_title_size = $(this).val();
  254. render_selected_card();
  255. }
  256. function on_change_default_icon_size() {
  257. options.icon_inline = $(this).is(':checked');
  258. render_selected_card();
  259. }
  260. // ============================================================================
  261. // Map/Filter
  262. // ============================================================================
  263. function apply_default_color() {
  264. deck.cards.forEach((card) => {
  265. card.color = options.default_color;
  266. });
  267. render_selected_card();
  268. }
  269. function apply_default_icon() {
  270. deck.cards.forEach((card) => {
  271. card.icon = options.default_icon;
  272. });
  273. render_selected_card();
  274. }
  275. function apply_default_icon_back() {
  276. deck.cards.forEach((card) => {
  277. card.icon_back = options.default_icon;
  278. });
  279. render_selected_card();
  280. }
  281. function sort() {
  282. showModal("#sort-modal");
  283. }
  284. function sort_execute() {
  285. hideModal("#sort-modal");
  286. var fn_code = $("#sort-function").val();
  287. var fn = new Function("card_a", "card_b", fn_code);
  288. deck.cards = deck.cards.sort(function (card_a, card_b) {
  289. var result = fn(card_a, card_b);
  290. return result;
  291. });
  292. update_card_list();
  293. }
  294. function filter() {
  295. showModal("#filter-modal");
  296. }
  297. function filter_execute() {
  298. hideModal("#filter-modal");
  299. var fn_code = $("#filter-function").val();
  300. var fn = new Function("card", "deck", fn_code);
  301. deck.cards.forEach((card) => {
  302. fn(card, deck);
  303. });
  304. deck.commit();
  305. update_card_list();
  306. }
  307. // ============================================================================
  308. // Modals
  309. // ============================================================================
  310. function showModal(id: string) {
  311. (<any>$(id)).modal('show');
  312. }
  313. function hideModal(id: string) {
  314. (<any>$(id)).modal('hide');
  315. }
  316. // ============================================================================
  317. // I/O
  318. // ============================================================================
  319. function save_file() {
  320. var str = JSON.stringify(deck.toJSON(), null, " ");
  321. var parts = [str];
  322. var blob = new Blob(parts, { type: 'application/json' });
  323. var url = URL.createObjectURL(blob);
  324. var a = <HTMLLinkElement>$("#file-save-link")[0];
  325. a.href = url;
  326. (<any>a).download = "rpg_cards.json";
  327. a.click();
  328. setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
  329. }
  330. function load_sample() {
  331. deck = RpgCards.CardDeck.fromJSON(card_data_example);
  332. update_card_list();
  333. }
  334. function clear_all() {
  335. deck = new RpgCards.CardDeck();
  336. update_card_list();
  337. }
  338. function ui_load_files(evt) {
  339. // ui_clear_all();
  340. var files = evt.target.files;
  341. for (var i = 0, f; f = files[i]; i++) {
  342. var reader = new FileReader();
  343. reader.onload = function (reader) {
  344. var data = JSON.parse(this.result);
  345. var deck = RpgCards.CardDeck.fromJSON(data);
  346. add_cards(deck.cards);
  347. };
  348. reader.readAsText(f);
  349. }
  350. // Reset file input
  351. (<any>$("#file-load-form")[0]).reset();
  352. }
  353. function add_cards(cards: RpgCards.Card[]) {
  354. deck.addCards(cards);
  355. update_card_list();
  356. }
  357. function add_new_card() {
  358. deck.addNewCard();
  359. update_card_list();
  360. select_card_by_index(deck.cards.length - 1);
  361. }
  362. function duplicate_card() {
  363. var newCard = null;
  364. if (deck.cards.length > 0) {
  365. var old_card = selected_card();
  366. newCard = deck.duplicateCard(old_card);
  367. } else {
  368. newCard = deck.addNewCard();
  369. }
  370. update_card_list();
  371. select_card_by_card(newCard);
  372. }
  373. function delete_card() {
  374. var index = selected_card_index();
  375. var card = selected_card();
  376. deck.deleteCard(card);
  377. update_card_list();
  378. select_card_by_index(Math.min(index, deck.cards.length - 1));
  379. }
  380. // ============================================================================
  381. // Menu
  382. // ============================================================================
  383. function open_help() {
  384. showModal("#help-modal");
  385. }
  386. function select_icon() {
  387. window.open("http://game-icons.net/", "_blank");
  388. }
  389. var generate_modal_shown = false;
  390. function generate() {
  391. if (deck.cards.length === 0) {
  392. alert("Your deck is empty. Please define some cards first, or load the sample deck.");
  393. return;
  394. }
  395. // Generate output HTML
  396. var card_html = pageGenerator.generateHtml(deck.cards, options);
  397. // Open a new window for the output
  398. // Use a separate window to avoid CSS conflicts
  399. var tab = window.open("output.html", 'rpg-cards-output');
  400. if (generate_modal_shown == false) {
  401. showModal("#print-modal");
  402. generate_modal_shown = true;
  403. }
  404. // Send the generated HTML to the new window
  405. // Use a delay to give the new window time to set up a message listener
  406. setTimeout(function () { tab.postMessage(card_html, '*') }, 500);
  407. }
  408. function collapse_menu() {
  409. $("#menu-column").hide();
  410. $("#card-column").removeClass("col-lg-5");
  411. $("#card-column").addClass("col-lg-8");
  412. editor.resize();
  413. }
  414. function uncollapse_menu() {
  415. $("#menu-column").show();
  416. $("#card-column").removeClass("col-lg-8");
  417. $("#card-column").addClass("col-lg-5");
  418. editor.resize();
  419. }
  420. export function toggle_menu() {
  421. if ($("#menu-column").is(":visible")) {
  422. collapse_menu();
  423. } else {
  424. uncollapse_menu();
  425. }
  426. }
  427. // ============================================================================
  428. // Initialization
  429. // ============================================================================
  430. function init() {
  431. deck = new RpgCards.CardDeck();
  432. options = new RpgCards.Options();
  433. cardGenerator = new RpgCards.CardHtmlGenerator;
  434. pageGenerator = new RpgCards.PageHtmlGenerator;
  435. editor = ace.edit("card-contents");
  436. editor.setShowInvisibles(true);
  437. editor.renderer.setShowGutter(false);
  438. (<any>editor).setOption("wrap", "free");
  439. editor.setTheme("ace/theme/chrome");
  440. editor.getSession().setMode("ace/mode/rpgcard");
  441. (<any>editor).$blockScrolling = Infinity;
  442. setup_color_selector();
  443. (<any>$('.icon-list')).typeahead({ source: icon_names });
  444. // Menu
  445. $("#sort-execute").click(sort_execute);
  446. $("#filter-execute").click(filter_execute);
  447. $("#button-generate").click(generate);
  448. $("#button-load").click(function () { $("#file-load").click(); });
  449. $("#file-load").change(ui_load_files);
  450. $("#button-clear").click(clear_all);
  451. $("#button-load-sample").click(load_sample);
  452. $("#button-save").click(save_file);
  453. $("#button-sort").click(sort);
  454. $("#button-filter").click(filter);
  455. $("#button-add-card").click(add_new_card);
  456. $("#button-duplicate-card").click(duplicate_card);
  457. $("#button-delete-card").click(delete_card);
  458. $("#button-help").click(open_help);
  459. $("#button-apply-color").click(apply_default_color);
  460. $("#button-apply-icon").click(apply_default_icon);
  461. $("#button-apply-icon-back").click(apply_default_icon_back);
  462. $("#selected-card").change(update_selected_card);
  463. $("#card-title").change(on_change_card_title);
  464. $("#card-title-size").change(on_change_card_property);
  465. $("#card-title-icon-text").change(on_change_card_property);
  466. $("#card-icon").change(on_change_card_property);
  467. $("#card-count").change(on_change_card_property);
  468. $("#card-icon-back").change(on_change_card_property);
  469. $("#card-color").change(on_change_card_color);
  470. editor.getSession().on('change', on_change_card_contents);
  471. //$("#card-contents").change(on_change_card_contents);
  472. $("#card-tags").change(on_change_card_tags);
  473. // Global options
  474. $("#page-size").change(on_change_option);
  475. $("#page-rows").change(on_change_option);
  476. $("#page-columns").change(on_change_option);
  477. $("#card-arrangement").change(on_change_option);
  478. $("#card-size").change(on_change_option);
  479. $("#background-color").change(on_change_option);
  480. $("#default-color").change(on_change_default_color);
  481. $("#default-icon").change(on_change_default_icon);
  482. $("#default-title-size").change(on_change_default_title_size);
  483. $("#small-icons").change(on_change_default_icon_size);
  484. $(".icon-select-button").click(select_icon);
  485. // Shortcuts
  486. var shortcut_options = { disable_in_input: true };
  487. shortcut.add("ctrl+m", toggle_menu, shortcut_options);
  488. shortcut.add("ctrl+n", add_new_card, shortcut_options);
  489. shortcut.add("ctrl+d", duplicate_card, shortcut_options);
  490. shortcut.add("delete", delete_card, shortcut_options);
  491. shortcut.add("down", select_next_card, shortcut_options);
  492. shortcut.add("page_down", select_next_card, shortcut_options);
  493. shortcut.add("up", select_prev_card, shortcut_options);
  494. shortcut.add("page_up", select_prev_card, shortcut_options);
  495. shortcut.add("home", select_first_card, shortcut_options);
  496. shortcut.add("end", select_last_card, shortcut_options);
  497. update_card_list();
  498. }
  499. $(document).ready(function () {
  500. init();
  501. });
  502. }