editor.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. $(document).ready(function() {
  2. function getParameters() {
  3. var parameters = {};
  4. window.location.search.substr(1).split('&').forEach(function(pair) {
  5. if (pair === '') return;
  6. var parts = pair.split('=');
  7. if (parts.length === 2 && parts[1].search(/^(true|1)$/i) >= 0) {
  8. parameters[parts[0]] = true;
  9. }
  10. else if (parts.length === 2 && parts[1].search(/^(false|0)$/i) >= 0) {
  11. parameters[parts[0]] = false;
  12. }
  13. else parameters[parts[0]] = parts[1] && decodeURIComponent(parts[1].replace(/\+/g, ' '));
  14. });
  15. return {
  16. get: function(name, defaultValue) {
  17. if (parameters.hasOwnProperty(name)) return parameters[name];
  18. return defaultValue;
  19. }
  20. };
  21. }
  22. var parameters = getParameters();
  23. if (parameters.get('test', false)) {
  24. var li = $('<li>Tests</li>');
  25. var ul = $('<ul>');
  26. for (var i = 1; i <= 8; ++i) {
  27. ul.append($('<li id="examples-test' + i + '">Test ' + i + '</li>'));
  28. }
  29. li.append(ul);
  30. $('#main-menu').append(li);
  31. }
  32. function handleFind(column) {
  33. if (!column.length) {
  34. return false;
  35. }
  36. var ed = $('#mergely');
  37. var find = column.find('.find');
  38. var input = find.find('input[type="text"]');
  39. var side = column.attr('id').indexOf('-lhs') > 0 ? 'lhs' : 'rhs';
  40. var origautoupdate = ed.mergely('options').autoupdate;
  41. find.slideDown('fast', function() {
  42. input.focus();
  43. // disable autoupdate, clear both sides of diff
  44. ed.mergely('options', {autoupdate: false});
  45. ed.mergely('unmarkup');
  46. });
  47. find.find('.find-prev').click(function() {
  48. ed.mergely('search', side, input.val(), 'prev');
  49. });
  50. find.find('.find-next').click(function() {
  51. ed.mergely('search', side, input.val(), 'next');
  52. });
  53. find.find('.find-close').click(function() {
  54. find.css('display', 'none')
  55. ed.mergely('options', {autoupdate: origautoupdate});
  56. });
  57. input.keydown(function(evt) {
  58. if (evt.which != 13 && evt.which != 27) return true;
  59. if (evt.which == 27) {
  60. find.css('display', 'none');
  61. ed.mergely('options', {autoupdate: origautoupdate});
  62. }
  63. ed.mergely('search', side, input.val());
  64. return false;
  65. });
  66. }
  67. $(document).keydown(function(event) {
  68. if (!( String.fromCharCode(event.which).toLowerCase() == 'f' && event.ctrlKey)) return true;
  69. event.preventDefault();
  70. var range = window.getSelection().getRangeAt(0);
  71. var column = $(range.commonAncestorContainer).parents('.mergely-column');
  72. handleFind(column);
  73. return false;
  74. });
  75. String.prototype.random = function(length) {
  76. var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
  77. var randomstring = ''
  78. for (var i=0; i<length; i++) {
  79. var rnum = Math.floor(Math.random() * chars.length);
  80. randomstring += chars.substring(rnum,rnum+1);
  81. }
  82. return randomstring;
  83. }
  84. // body is pre-hidden for better rendering
  85. $('body').css("visibility", "");
  86. var ed = $('#mergely');
  87. var menu = $('#main-menu');
  88. var toolbar = $('#toolbar');
  89. ed.mergely({
  90. width: 'auto',
  91. height: 'auto',
  92. cmsettings: {
  93. lineNumbers: true,
  94. readOnly: isSample
  95. }
  96. });
  97. if (parameters.get('lhs', null)) {
  98. var url = parameters.get('lhs');
  99. crossdomainGET(ed, 'lhs', url);
  100. }
  101. if (parameters.get('rhs', null)) {
  102. var url = parameters.get('rhs');
  103. crossdomainGET(ed, 'rhs', url);
  104. }
  105. // set query string options
  106. var urloptions = {};
  107. var optmap = {
  108. au: 'autoupdate',
  109. ws: 'ignorews',
  110. cs: 'ignorecase',
  111. sb: 'sidebar',
  112. vp: 'viewport',
  113. wl: 'wrap_lines',
  114. ln: 'line_numbers'
  115. };
  116. var doopt = false;
  117. for (var name in optmap) {
  118. if (!optmap.hasOwnProperty(name)) continue;
  119. if (parameters.get(name, null) !== null) {
  120. urloptions[optmap[name]] = parameters.get(name);
  121. doopt = true;
  122. }
  123. }
  124. if (parameters.get('rm', null) !== null) {
  125. // special-case url property
  126. urloptions.rhs_margin = parameters.get('rm') ? 'left' : 'right';
  127. }
  128. if (doopt) {
  129. // apply query-string options
  130. ed.mergely('options', urloptions);
  131. }
  132. // set query string colors
  133. // cb: change border
  134. // cg: change background
  135. // ab: added border
  136. // ag: added background
  137. // db: deleted border
  138. // dg: deleted background
  139. var color_defaults = {
  140. cb: 'cccccc', cg: 'fafafa',
  141. ab: 'a3d1ff', ag: 'ddeeff',
  142. db: 'ff7f7f', dg: 'ffe9e9'
  143. };
  144. applyParameterCss(false);
  145. //history.pushState({}, null, '');
  146. window.addEventListener('popstate', function(ev) {
  147. if (ev.state) {
  148. parameters = getParameters();
  149. applyParameterCss(false);
  150. }
  151. });
  152. // Load
  153. if (key.length == 8) {
  154. $.when(
  155. $.ajax({
  156. type: 'GET', async: true, dataType: 'text',
  157. data: { 'key':key, 'name': 'lhs' },
  158. url: '/ajax/handle_get.php',
  159. success: function (response) {
  160. ed.mergely('lhs', response);
  161. },
  162. error: function(xhr, ajaxOptions, thrownError){
  163. }
  164. }),
  165. $.ajax({
  166. type: 'GET', async: true, dataType: 'text',
  167. data: { 'key':key, 'name': 'rhs' },
  168. url: '/ajax/handle_get.php',
  169. success: function (response) {
  170. ed.mergely('rhs', response);
  171. },
  172. error: function(xhr, ajaxOptions, thrownError){
  173. }
  174. })
  175. ).done(function() {
  176. var anchor = window.location.hash.substring(1);
  177. if (anchor) {
  178. // if an anchor has been provided, then parse the anchor in the
  179. // form of: 'lhs' or 'rhs', followed by a line, e.g: lhs100.
  180. var m = anchor.match(/([lr]hs)([0-9]+)/);
  181. if (m && m.length == 3) {
  182. console.log(m);
  183. ed.mergely('scrollTo', m[1], parseInt(m[2],10));
  184. }
  185. }
  186. });
  187. }
  188. // find
  189. var find = $('.find');
  190. var flhs = find.clone().attr('id', 'mergely-editor-lhs-find');
  191. var frhs = find.clone().attr('id', 'mergely-editor-rhs-find');
  192. $('#mergely-editor-lhs').append(flhs);
  193. $('#mergely-editor-rhs').append(frhs);
  194. find.remove();
  195. var iconconf = {
  196. 'options-autodiff': {
  197. get: function() { return ed.mergely('options').autoupdate },
  198. set: function(value) {
  199. var au = !ed.mergely('options').autoupdate;
  200. ed.mergely('options', {autoupdate: au});
  201. var params = updateQueryStringParam('au', au ? 1 : 0, 1);
  202. updateHistory(params);
  203. }
  204. },
  205. 'options-ignorews': {
  206. get: function() { return ed.mergely('options').ignorews },
  207. set: function(value) {
  208. var ws = !ed.mergely('options').ignorews;
  209. ed.mergely('options', {ignorews: ws});
  210. var params = updateQueryStringParam('ws', ws ? 1 : 0, 0);
  211. updateHistory(params);
  212. }
  213. },
  214. 'options-ignorecase': {
  215. get: function() { return ed.mergely('options').ignorecase },
  216. set: function(value) {
  217. var cs = !ed.mergely('options').ignorecase;
  218. ed.mergely('options', {ignorecase: cs});
  219. var params = updateQueryStringParam('cs', cs ? 1 : 0, 0);
  220. updateHistory(params);
  221. }
  222. },
  223. 'options-sidebars': {
  224. get: function() { console.log('sidebar', this); return ed.mergely('options').sidebar },
  225. set: function(value) {
  226. var sb = !ed.mergely('options').sidebar;
  227. ed.mergely('options', {sidebar: sb});
  228. var params = updateQueryStringParam('sb', sb ? 1 : 0, 1);
  229. updateHistory(params);
  230. }
  231. },
  232. 'options-viewport': {
  233. get: function() { console.log('viewport', this); return ed.mergely('options').viewport },
  234. set: function(value) {
  235. var vp = !ed.mergely('options').viewport;
  236. ed.mergely('options', {viewport: vp});
  237. var params = updateQueryStringParam('vp', vp ? 1 : 0, 0);
  238. updateHistory(params);
  239. }
  240. },
  241. 'options-swapmargin': {
  242. get: function() { return (ed.mergely('options').rhs_margin == 'left'); },
  243. set: function(value) {
  244. var rm = ed.mergely('options').rhs_margin == 'left' ? 'right' : 'left';
  245. ed.mergely('options', {rhs_margin: rm });
  246. var params = updateQueryStringParam('rm', rm == 'left' ? 1 : 0, 0);
  247. updateHistory(params);
  248. }
  249. },
  250. 'options-linenumbers': {
  251. get: function() { console.log('wrap', this); return ed.mergely('options').line_numbers },
  252. set: function(value) {
  253. var ln = !ed.mergely('options').line_numbers;
  254. ed.mergely('options', {line_numbers: ln});
  255. var params = updateQueryStringParam('ln', ln ? 1 : 0, 1);
  256. updateHistory(params);
  257. }
  258. },
  259. 'options-wrap': {
  260. get: function() { console.log('wrap', this); return ed.mergely('options').wrap_lines },
  261. set: function(value) {
  262. var wl = !ed.mergely('options').wrap_lines;
  263. ed.mergely('options', {wrap_lines: wl});
  264. var params = updateQueryStringParam('wl', wl ? 1 : 0, 0);
  265. updateHistory(params);
  266. }
  267. },
  268. 'edit-left-readonly': {
  269. get: function() { return ed.mergely('cm', 'lhs').getOption('readOnly'); },
  270. set: function(value) { ed.mergely('cm', 'lhs').setOption('readOnly', value); }
  271. },
  272. 'edit-right-readonly': {
  273. get: function() { return ed.mergely('cm', 'rhs').getOption('readOnly'); },
  274. set: function(value) { ed.mergely('cm', 'rhs').setOption('readOnly', value); }
  275. }
  276. }
  277. var menu_opts = {
  278. hasIcon: function(id) {
  279. return iconconf.hasOwnProperty(id);
  280. },
  281. getIcon: function(id) {
  282. if (iconconf[id].get()) return 'icon-check';
  283. }
  284. };
  285. function handle_operation(id) {
  286. if (id == 'file-new') {
  287. window.location = '/editor';
  288. }
  289. else if (id == 'file-save') {
  290. // download directly from browser
  291. var text = ed.mergely('diff');
  292. if (navigator.userAgent.toLowerCase().indexOf('msie') === -1) {
  293. if (key == '') key = ''.random(8);
  294. var link = jQuery('<a />', {
  295. href: 'data:application/stream;base64,' + window.btoa(unescape(encodeURIComponent(text))),
  296. target: '_blank',
  297. text: 'clickme',
  298. id: key
  299. });
  300. link.attr('download', key + '.diff');
  301. jQuery('body').append(link);
  302. var a = $('a#' + key);
  303. a[0].click();
  304. a.remove();
  305. }
  306. else {
  307. var blob = new Blob([text]);
  308. window.navigator.msSaveOrOpenBlob(blob, key + '.diff');
  309. }
  310. }
  311. else if (id == 'file-share') {
  312. handleShare(ed);
  313. }
  314. else if (id == 'file-import') {
  315. importFiles(ed);
  316. }
  317. else if (id == 'edit-left-undo') {
  318. ed.mergely('cm', 'lhs').getDoc().undo();
  319. }
  320. else if (id == 'edit-left-redo') {
  321. ed.mergely('cm', 'lhs').getDoc().redo();
  322. }
  323. else if (id == 'edit-right-undo') {
  324. ed.mergely('cm', 'rhs').getDoc().undo();
  325. }
  326. else if (id == 'edit-right-redo') {
  327. ed.mergely('cm', 'rhs').getDoc().redo();
  328. }
  329. else if (id == 'edit-left-find') {
  330. handleFind(ed.find('#mergely-editor-lhs'));
  331. }
  332. else if (id == 'edit-left-merge-right') {
  333. ed.mergely('mergeCurrentChange', 'rhs');
  334. }
  335. else if (id == 'edit-left-merge-right-file') {
  336. ed.mergely('merge', 'rhs');
  337. }
  338. else if ([
  339. 'edit-left-readonly',
  340. 'edit-right-readonly',
  341. 'options-autodiff',
  342. 'options-sidebars',
  343. 'options-swapmargin',
  344. 'options-viewport',
  345. 'options-ignorews',
  346. 'options-ignorecase',
  347. 'options-wrap',
  348. 'options-linenumbers',
  349. ].indexOf(id) >= 0) {
  350. iconconf[id].set(!iconconf[id].get());
  351. menu.wickedmenu('update', id);
  352. }
  353. else if (id == 'edit-left-clear') {
  354. ed.mergely('clear', 'lhs');
  355. }
  356. else if (id == 'edit-right-find') {
  357. handleFind(ed.find('#mergely-editor-rhs'));
  358. }
  359. else if (id == 'edit-right-merge-left') {
  360. ed.mergely('mergeCurrentChange', 'lhs');
  361. }
  362. else if (id == 'edit-right-merge-left-file') {
  363. ed.mergely('merge', 'lhs');
  364. }
  365. else if (id == 'edit-right-clear') {
  366. ed.mergely('clear', 'rhs');
  367. }
  368. else if (id == 'options-colors') {
  369. colorSettings(ed);
  370. }
  371. else if (id == 'view-swap') {
  372. ed.mergely('swap');
  373. }
  374. else if (id == 'view-refresh') {
  375. ed.mergely('update');
  376. }
  377. else if (id == 'view-change-next') {
  378. ed.mergely('scrollToDiff', 'next');
  379. }
  380. else if (id == 'view-change-prev') {
  381. ed.mergely('scrollToDiff', 'prev');
  382. }
  383. else if (id == 'view-clear') {
  384. ed.mergely('unmarkup');
  385. }
  386. else if (id.indexOf('examples-') == 0) {
  387. var test_config = {
  388. test1: {lhs: 'one\ntwo\nthree', rhs: 'two\nthree'},
  389. test2: {lhs: 'two\nthree', rhs: 'one\ntwo\nthree'},
  390. test3: {lhs: 'one\nthree', rhs: 'one\ntwo\nthree'},
  391. test4: {lhs: 'one\ntwo\nthree', rhs: 'one\nthree'},
  392. test5: {lhs: 'to bee, or not to be', rhs: 'to be, or not to bee'},
  393. test6: {lhs: 'to be, or not to be z', rhs: 'to be, to be'},
  394. test7: {lhs: 'remained, & to assume', rhs: 'and to assume'},
  395. test8: {lhs: 'to be, or not to be', rhs: 'to be, or not to be'}
  396. };
  397. var test = id.split('examples-')[1];
  398. ed.mergely('lhs', test_config[test]['lhs']);
  399. ed.mergely('rhs', test_config[test]['rhs']);
  400. }
  401. return false;
  402. }
  403. menu.wickedmenu(menu_opts).bind('selected', function(ev, id) {
  404. return handle_operation(id);
  405. });
  406. toolbar.wickedtoolbar({}).bind('selected', function(ev, id) {
  407. if (!id) return false;
  408. return handle_operation(id.replace(/^tb-/, ''));
  409. });
  410. toolbar.find('li[title]').tipsy({opacity: 1});
  411. menu.find('li[title]').tipsy({opacity: 1, delayIn: 1000, gravity: 'w'});
  412. function handleShare(ed) {
  413. var fork = $(this).attr('id') == 'fork';
  414. if (key == '') key = ''.random(8);
  415. var count = 0;
  416. function post_save(side, text) {
  417. $.ajax({
  418. type: 'POST', async: true, dataType: 'text',
  419. url: '/ajax/handle_file.php',
  420. data: { 'key': key, 'name': side, 'content': text },
  421. success: function (nkey) {
  422. ++count;
  423. if (count == 2) {
  424. var url = '/ajax/handle_save.php?key=' + key;
  425. if (fork) url += '&nkey=' + ''.random(8);
  426. $.ajax({
  427. type: 'GET', async: false, dataType: 'text',
  428. url: url,
  429. success: function (nkey) {
  430. // redirect
  431. if (nkey.length) window.location.href = '/' + $.trim(nkey) + '/';
  432. },
  433. error: function(xhr, ajaxOptions, thrownError){
  434. }
  435. });
  436. }
  437. },
  438. error: function(xhr, ajaxOptions, thrownError){
  439. alert(thrownError);
  440. }
  441. });
  442. }
  443. function save_files() {
  444. var lhs = ed.mergely('get', 'lhs');
  445. var rhs = ed.mergely('get', 'rhs');
  446. post_save('lhs', lhs);
  447. post_save('rhs', rhs);
  448. }
  449. $( '#dialog-confirm' ).dialog({
  450. resizable: false, width: 350, modal: true,
  451. buttons: {
  452. 'Save for Sharing': function() {
  453. $( this ).dialog( 'close' );
  454. save_files();
  455. },
  456. Cancel: function() {
  457. $( this ).dialog( 'close' );
  458. }
  459. }
  460. });
  461. }
  462. function crossdomainGET(ed, side, url) {
  463. $.ajax({
  464. type: 'GET', dataType: 'text',
  465. data: {url: url},
  466. url: '/ajax/handle_crossdomain.php',
  467. contentType: 'text/plain',
  468. success: function (response) {
  469. ed.mergely(side, response);
  470. },
  471. error: function(xhr, ajaxOptions, thrownError){
  472. console.error('error', xhr, ajaxOptions, thrownError);
  473. }
  474. });
  475. }
  476. function importFiles(ed) {
  477. // -------------
  478. // file uploader - html5 file upload to browser
  479. function file_load(target, side) {
  480. var file = target.files[0];
  481. var reader = new FileReader();
  482. var $target = $(target);
  483. function trigger(name, event) { $target.trigger(name, event); }
  484. reader.onloadstart = function(evt) { trigger('start'); }
  485. reader.onprogress = function(evt) { trigger('progress', evt); }
  486. reader.onload = function(evt) { trigger('loaded', evt.target.result); }
  487. reader.onerror = function (evt) {
  488. alert(evt.target.error.name);
  489. }
  490. try {
  491. reader.readAsText(file, 'UTF-8');
  492. }
  493. catch (e) {
  494. console.error(e);
  495. alert(e);
  496. }
  497. }
  498. var file_data = {};
  499. $('#file-lhs, #file-rhs').change(function (evt) {
  500. var re = new RegExp('.*[\\\\/](.*)$');
  501. var match = re.exec($(this).val());
  502. var fname = match ? match[1] : 'unknown';
  503. var progressbar = $('#' + evt.target.id + '-progress');
  504. file_load(evt.target);
  505. $(evt.target).bind('start', function(ev){
  506. $(evt.target).css('display', 'none');
  507. progressbar.css('display', 'inline-block');
  508. });
  509. $(evt.target).bind('progress', function(ev, progress){
  510. var loaded = (progress.loaded / progress.total) * 100;
  511. progressbar.find('> .progress-label').text(loaded + '%');
  512. progressbar.progressbar('value', loaded);
  513. });
  514. $(evt.target).bind('loaded', function(ev, file){
  515. progressbar.progressbar('value', 100);
  516. progressbar.find('> .progress-label').text(fname);
  517. file_data[evt.target.id] = file;
  518. });
  519. });
  520. $('#file-lhs-progress').progressbar({value: 0});
  521. $('#file-rhs-progress').progressbar({value: 0});
  522. $('#dialog-upload .tabs').tabs();
  523. function callbackName(data) {
  524. console.log('callbackName', data);
  525. }
  526. $('#dialog-upload').dialog({
  527. dialogClass: 'no-title',
  528. resizable: false,
  529. width: '450px',
  530. modal: true,
  531. buttons: {
  532. Import: function() {
  533. $(this).dialog('close');
  534. var urls = { lhs: $('#url-lhs').val(), rhs: $('#url-rhs').val() };
  535. for (var side in urls) {
  536. var url = urls[side];
  537. if (!url) continue;
  538. crossdomainGET(ed, side, url);
  539. }
  540. if (file_data.hasOwnProperty('file-lhs')) {
  541. ed.mergely('lhs', file_data['file-lhs']);
  542. }
  543. if (file_data.hasOwnProperty('file-rhs')) {
  544. ed.mergely('rhs', file_data['file-rhs']);
  545. }
  546. },
  547. Cancel: function() {
  548. $(this).dialog('close');
  549. }
  550. }
  551. });
  552. }
  553. function colorSettings(ed) {
  554. // get current settings
  555. var sd = $('<span style="display:none" class="mergely ch d lhs start end">C</span>');
  556. var sa = $('<span style="display:none" class="mergely bg a rhs start end">C</span>');
  557. var sc = $('<span style="display:none" class="mergely c rhs start end">C</span>');
  558. $('body').append(sd);
  559. $('body').append(sa);
  560. $('body').append(sc);
  561. var conf = {
  562. 'c-border': {id: '#c-border', getColor: function() { return sc.css('border-top-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
  563. 'c-bg': {id: '#c-bg', getColor: function() { return sc.css('background-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
  564. 'a-border': {id: '#a-border', getColor: function() { return sa.css('border-top-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
  565. 'a-bg': {id: '#a-bg', getColor: function() { return sa.css('background-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
  566. 'd-border': {id: '#d-border', getColor: function() { return sd.css('border-top-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
  567. 'd-bg': {id: '#d-bg', getColor: function() { return sd.css('background-color'); }, setColor: function(color) { $('#'+this.id).val(color) }}
  568. };
  569. $.each(conf, function(key, item){$(item.id).val(item.getColor()); });
  570. var f = $.farbtastic('#picker');
  571. $('.colorwell').each(function(){ f.linkTo(this); }).focus(function(){
  572. var tthis = $(this);
  573. f.linkTo(this);
  574. var item = conf[tthis.attr('id')];
  575. f.setColor(item.getColor());
  576. });
  577. $('#dialog-colors').dialog({
  578. width: 490, modal: true,
  579. buttons: {
  580. Apply: function() {
  581. var cborder = $('#c-border').val();
  582. var aborder = $('#a-border').val();
  583. var dborder = $('#d-border').val();
  584. var abg = $('#a-bg').val();
  585. var dbg = $('#d-bg').val();
  586. var cbg = $('#c-bg').val();
  587. var textCss = makeColorCss(cborder, cbg, aborder, abg, dborder, dbg);
  588. applyColorCss(textCss, cborder, cbg, aborder, abg, dborder, dbg, true);
  589. },
  590. Reset: function() {
  591. },
  592. Close: function() {
  593. $(this).dialog('close');
  594. }
  595. }
  596. });
  597. }
  598. function makeColorCss(changeBorder, changeBackground, addedBorder, addedBackground, deletedBorder, deletedBackground) {
  599. var text =
  600. '.mergely.a.rhs.start{border-top-color:' + addedBorder + ';}\n\
  601. .mergely.a.lhs.start.end,\n\
  602. .mergely.a.rhs.end{border-bottom-color:' + addedBorder + ';}\n\
  603. .mergely.a.rhs{background-color:' + addedBackground + ';}\n\
  604. .mergely.d.lhs{background-color:' + deletedBackground + ';}\n\
  605. .mergely.d.lhs.end,\n\
  606. .mergely.d.rhs.start.end{border-bottom-color:' + deletedBorder + ';}\n\
  607. .mergely.d.rhs.start.end.first{border-top-color:' + deletedBorder + ';}\n\
  608. .mergely.d.lhs.start{border-top-color:' + deletedBorder + ';}\n\
  609. .mergely.c.lhs,\n\
  610. .mergely.c.rhs{background-color:' + changeBackground + ';}\n\
  611. .mergely.c.lhs.start,\n\
  612. .mergely.c.rhs.start{border-top-color:' + changeBorder + ';}\n\
  613. .mergely.c.lhs.end,\n\
  614. .mergely.c.rhs.end{border-bottom-color:' + changeBorder + ';}\n\
  615. .mergely.ch.a.rhs{background-color:' + addedBackground + ';}\n\
  616. .mergely.ch.d.lhs{background-color:' + deletedBackground + ';color: #888;}';
  617. return text;
  618. }
  619. function applyParameterCss(saveState) {
  620. var cb = '#' + parameters.get('cb',color_defaults.cb),
  621. cg = '#' + parameters.get('cg',color_defaults.cg),
  622. ab = '#' + parameters.get('ab',color_defaults.ab),
  623. ag = '#' + parameters.get('ag',color_defaults.ag),
  624. db = '#' + parameters.get('db',color_defaults.db),
  625. dg = '#' + parameters.get('dg',color_defaults.dg);
  626. applyColorCss(makeColorCss(cb, cg, ab, ag, db, dg), cb, cg, ab, ag, db, dg, saveState);
  627. }
  628. function applyColorCss(cssText, changeBorder, changeBackground, addedBorder, addedBackground, deletedBorder, deletedBackground, saveState) {
  629. $('<style type="text/css">' + cssText + '</style>').appendTo('head');
  630. ed.mergely('options', {
  631. fgcolor:{a:addedBorder,c:changeBorder,d:deletedBorder}
  632. });
  633. var params = updateQueryStringParam('cb', changeBorder.replace(/#/g, ''), color_defaults.cb);
  634. params = updateQueryStringParam('cg', changeBackground.replace(/#/g, ''), color_defaults.cg, params);
  635. params = updateQueryStringParam('ab', addedBorder.replace(/#/g, ''), color_defaults.ab, params);
  636. params = updateQueryStringParam('ag', addedBackground.replace(/#/g, ''), color_defaults.ag, params);
  637. params = updateQueryStringParam('db', deletedBorder.replace(/#/g, ''), color_defaults.db, params);
  638. params = updateQueryStringParam('dg', deletedBackground.replace(/#/g, ''), color_defaults.dg, params);
  639. if (saveState) {
  640. updateHistory(params);
  641. }
  642. }
  643. function updateHistory(params) {
  644. var baseUrl = [location.protocol, '//', location.host, location.pathname].join('');
  645. window.history.pushState({}, null, baseUrl + params);
  646. }
  647. // Explicitly save/update a url parameter using HTML5's replaceState().
  648. function updateQueryStringParam(key, value, defaultValue, urlQueryString) {
  649. urlQueryString = urlQueryString || document.location.search;
  650. var parts = urlQueryString.replace(/^\?/, '').split(/&/), found = false;
  651. for (var i in parts) {
  652. if (parts[i].startsWith(key + '=')) {
  653. found = true;
  654. if (value === defaultValue) {
  655. // value is default value, remove option
  656. parts.splice(i, 1);
  657. }
  658. else {
  659. // make new value
  660. parts[i] = key + '=' + value;
  661. }
  662. break;
  663. }
  664. else if (parts[i].length === 0) {
  665. parts.splice(i, 1);
  666. break;
  667. }
  668. }
  669. if (!found) {
  670. parts.push(key + '=' + value);
  671. }
  672. return (parts.length) ? '?' + parts.join('&') : '';
  673. }
  674. });