1 module tweet_table;
2 
3 import std.uri : encodeComponent;
4 import std.algorithm : map;
5 import std.utf : UTFException;
6 
7 import carbon.utils : toLiteral;
8 import carbon.templates;
9 
10 import awebview.gui.html,
11        awebview.gui.activity;
12 
13 import awebview.wrapper;
14 
15 import msgpack;
16 
17 
18 immutable HTMLTableFormat = q{
19 <div class="col-md-6">
20   <table class="table table-striped" id="%[id%]">
21     <thead><tr></tr></thead>
22     <tbody></tbody>
23   </table>
24 </div>
25 };
26 
27 
28 /**
29 need jQuery
30 */
31 class TweetTable : TemplateHTMLElement!(HTMLElement, HTMLTableFormat)
32 {
33     this(string id)
34     {
35         super(id, true);
36         theaders = ["image", "username", "tweet"];
37     }
38 
39 
40     @property 
41     auto theaders()
42     {
43         static struct THeaders
44         {
45             @property const(string[]) array() const { return _parent._ths; }
46             string opIndex(size_t idx) const { return _parent._ths[idx]; }
47 
48 
49             void opIndexAssign(string th, size_t idx)
50             {
51                 _parent._ths[idx] = th;
52                 _parent.theaders = _parent._ths;
53             }
54 
55 
56             void opOpAssign(string op : "~")(string th)
57             {
58                 this ~= [th];
59             }
60 
61 
62             void opOpAssign(string op : "~")(string[] ths)
63             {
64                 _parent._ths ~= ths;
65                 _parent.theaders = _parent._ths;
66             }
67 
68 
69           private:
70             TweetTable _parent;
71         }
72 
73         return THeaders(this);
74     }
75 
76 
77     @property
78     void theaders(string[] ths)
79     {
80         _ths = ths;
81         if(this.activity !is null)
82             rerenderingHeader();
83     }
84 
85 
86     override
87     void onStart(HTMLPage page)
88     {
89         if(auto p = this.id in page.activity.application.savedData){
90             ubyte[] myData = *p;
91 
92             auto pf = unpack!PackedField(*p);
93             this._ths = pf.ths;
94             this._tds = pf.tds;
95 
96             if(this._tds.length > 100)
97                 this._tds = this._tds[$-100 .. $];
98 
99             *p = pf.parentData;
100             super.onStart(page);
101             *p = myData;
102         }
103         else
104         {
105             super.onStart(page);
106         }
107     }
108 
109 
110     override
111     void onDestroy()
112     {
113         auto app = this.activity.application;
114 
115         super.onDestroy();
116 
117         PackedField pf;
118         pf.ths = _ths;
119         pf.tds = _tds;
120 
121         if(pf.tds.length > 100)
122             pf.tds = pf.tds[$-100 .. $];
123 
124         if(auto p = this.id in app.savedData)
125             pf.parentData = *p;
126 
127         app.savedData[this.id] = pack(pf);
128     }
129 
130 
131     override
132     void onLoad(bool isInit)
133     {
134         super.onLoad(isInit);
135 
136         rerenderingHeader();
137         rerenderingBody();
138     }
139 
140 
141     void rerenderingHeader()
142     {
143         auto app = appender!string();
144         app.formattedWrite("%-(<th>%s</th>%|%)", _ths.map!encodeComponent());
145 
146         activity[$(mixin(Lstr!"#%[id%] > thead > tr"))].innerHTML = app.data;
147     }
148 
149 
150     void rerenderingBody()
151     {
152         auto app = appender!string();
153         foreach_reverse(e; _tds){
154             try
155                 appendTR(app, e[0], e[1], e[2]);
156             catch(UTFException ex)
157                 appendTR(app, e[0], e[1], ex.to!string);
158         }
159 
160         activity[$(mixin(Lstr!"#%[id%] > tbody"))].innerHTML = app.data;
161     }
162 
163 
164     void addTweet(string imageURL, string username, string tweet)
165     {
166         _tds ~= [imageURL, username, tweet];
167         if(this.activity !is null){
168             auto app = appender!string();
169             appendTR(app, imageURL, username, tweet);
170 
171             activity[$(mixin(Lstr!"#%[id%] > tbody"))].prepend(app.data);
172         }
173     }
174 
175 
176     private
177     void appendTR(Writer)(ref Writer w, string imageURL, string username, string tweet)
178     {
179         w.put(mixin(Lstr!`<tr><td><img src=%[toLiteral(imageURL)%]></td><td>%[username%]</td><td>%[tweet%]</td></tr>`));
180     }
181 
182 
183   private:
184     string[] _ths;
185     string[3][] _tds;
186 
187     struct PackedField { string[] ths; string[3][] tds; ubyte[] parentData; }
188 }