Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Simple conflict resolution

  • Loading branch information...
commit 18e30271e1117bdbea54aa343a26a014ab0cef25 1 parent 2b1fca4
Sam Ruby authored

Showing 1 changed file with 64 additions and 15 deletions. Show diff stats Hide diff stats

  1. +64 15 demo/wiki.rb
79 demo/wiki.rb
@@ -2,6 +2,7 @@
2 2 require 'wunderbar'
3 3 require 'rdiscount'
4 4 require 'shellwords'
  5 +require 'digest/md5'
5 6
6 7 Dir.chdir WIKIDATA
7 8
@@ -38,24 +39,31 @@
38 39
39 40 # determine markup
40 41 if _.post? and @markup
41   - File.open(file, 'w') {|fh| fh.write @markup}
42 42 _header class: 'status' do
43 43 _h1 'Status'
44   - _.system 'git init' unless Dir.exist? '.git'
45   - if `git status --porcelain #{file}`.empty?
46   - _p 'Nothing changed'
  44 + if File.exist?(file) and Digest::MD5.hexdigest(File.read(file)) != @hash
  45 + _p 'Write conflict'
47 46 else
48   - _.system "git add #{file}"
49   - _.system "git commit -m #{@comment.shellescape} #{file}"
  47 + File.open(file, 'w') {|fh| fh.write @markup}
  48 + _.system 'git init' unless Dir.exist? '.git'
  49 + if `git status --porcelain #{file}`.empty?
  50 + _p 'Nothing changed'
  51 + else
  52 + _.system "git add #{file}"
  53 + _.system "git commit -m #{@comment.shellescape} #{file}"
  54 + end
50 55 end
51 56 end
  57 +
52 58 elsif File.exist? file
  59 + # existing file
53 60 if !rev or rev.empty?
54 61 @markup = File.read(file)
55 62 else
56 63 @markup = `git show #{rev}:#{file}`
57 64 flag = nil
58 65 end
  66 +
59 67 else
60 68 # new file: go directly into edit mode
61 69 @markup = "#{file}\n#{'-'*file.length}\n\nEnter your text here..."
@@ -63,7 +71,23 @@
63 71 end
64 72
65 73 # produce HTML
66   - if flag == '?'
  74 + if file == '_index'
  75 +
  76 + # index
  77 + index = Hash[`git ls-tree HEAD --name-only`.scan(/(\w+)()/)].
  78 + merge Hash[*`git status --porcelain`.scan(/(..) (\w+)/).flatten.reverse]
  79 + _table do
  80 + _tbody do
  81 + index.sort.each do |name, status|
  82 + _tr do
  83 + _td status
  84 + _td {_a name, href: name}
  85 + end
  86 + end
  87 + end
  88 + end
  89 +
  90 + elsif flag == '?'
67 91
68 92 # edit mode
69 93 _header do
@@ -74,6 +98,8 @@
74 98
75 99 _form action: file, method: 'post' do
76 100 _textarea @markup, name: 'markup', class: 'input'
  101 + _input type: 'hidden', name: 'hash',
  102 + value: Digest::MD5.hexdigest(@markup)
77 103 _div class: 'output' do
78 104 _ << RDiscount.new(@markup).to_html
79 105 end
@@ -118,18 +144,36 @@
118 144 setInterval(function() {
119 145 if (!dirty) return;
120 146 dirty = false;
121   - var markup = $('textarea[name=markup]').val();
122   - $.getJSON("#{SELF}", {markup: markup}, function(response) {
123   - var time = new Date(response.time).toLocaleTimeString();
124   - $('.message').text("Autosaved at " + time).show().fadeOut(5000);
  147 +
  148 + var params = {
  149 + markup: $('textarea[name=markup]').val(),
  150 + hash: $('input[name=hash]').val()
  151 + };
  152 +
  153 + $.getJSON("#{SELF}", params, function(_) {
  154 + $('input[name=hash]').val(_.hash);
  155 + if (_.time) {
  156 + var time = new Date(_.time).toLocaleTimeString();
  157 + $('.message').text("Autosaved at " + time).show().fadeOut(5000);
  158 + } else {
  159 + $('.input').val(_.markup).attr('readonly', 'readonly');
  160 + $('.message').css({'font-weight': 'bold'}).text(_.error).show();
  161 + }
125 162 });
126 163 }, 10000);
127 164
  165 + // regenerate output every 0.5 seconds
  166 + var updated = false;
  167 + setInterval(function() {
  168 + if (!updated) return;
  169 + updated = false;
  170 + $('.output').html(converter.makeHtml($('.input').val()));
  171 + }, 500);
  172 +
128 173 // update output pane and mark dirty whenever input changes
129 174 var converter = new Showdown.converter();
130 175 $('.input').bind('input', function() {
131   - dirty = true;
132   - $('.output').html(converter.makeHtml($(this).val()));
  176 + updated = dirty = true;
133 177 }).trigger('input');
134 178
135 179 // resize based on window size
@@ -143,8 +187,13 @@
143 187
144 188 # process autosave requests
145 189 Wunderbar.json do
146   - File.open(file, 'w') {|fh| fh.write @markup}
147   - {time: Time.now.to_i*1000}
  190 + hash = Digest::MD5.hexdigest(@markup)
  191 + if File.exist?(file) and Digest::MD5.hexdigest(File.read(file)) != @hash
  192 + {error: "Write conflict", markup: File.read(file), hash: hash}
  193 + else
  194 + File.open(file, 'w') {|fh| fh.write @markup} unless @hash == hash
  195 + {time: Time.now.to_i*1000, hash: hash}
  196 + end
148 197 end
149 198
150 199 __END__

0 comments on commit 18e3027

Please sign in to comment.
Something went wrong with that request. Please try again.