-
Notifications
You must be signed in to change notification settings - Fork 3
/
sharedmobile.js
326 lines (295 loc) · 11.1 KB
/
sharedmobile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/// <reference path="intellisense.js" />
//
//DONT use const in this file, as mobile supports older browsers
var SEP_IDHISTORY_MULTI = ".";
var g_strUserMeOption = "me";
var PREFIX_PLUSCOMMAND = "^"; //plus command starts with this (both card and board commands)
var PLUSCOMMAND_RESET = "^resetsync";
var PLUSCOMMAND_ETRANSFER = "^etransfer";
var PLUSCOMMAND_ETRANSFER_FROMCARD = ".fromcard:";
var g_prefixCommentTransfer = "[" + PLUSCOMMAND_ETRANSFER;
var g_prefixCommentTransferTo = g_prefixCommentTransfer + " to ";
var g_prefixCommentTransferFrom = g_prefixCommentTransfer + " from ";
var g_dDaysMinimum = -10000; //sane limit of how many days back can be set on a S/E comment. limit is inclusive
var TAG_RECURRING_CARD = "[R]";
var DEFAULTGLOBAL_USER = "global";
var g_strUserOtherOption = "other user...";
var g_strDateOtherOption = "other date...";
var g_valMaxDaysCombo = 5;
var MAP_UNITS = {
"m": 1000 * 60,
"h": 1000 * 60 * 60,
"d": 1000 * 60 * 60 * 24
};
var UNITS = {
minutes: "m",
hours: "h",
days: "d",
current: "h", //current units, hours by default
callbackOnSet: null,
getCurrentShort: function (bDisplayPointUnits) {
if (bDisplayPointUnits)
return "p";
return this.current;
},
getLongFormat: function (u, bDisplayPointUnits) {
u = u || this.current;
if (bDisplayPointUnits)
return "points";
if (u == this.minutes)
return "minutes";
if (u == this.hours)
return "hours";
if (u == this.days)
return "days";
logPlusError("unknown units");
return "unknown";
},
SetCallbackOnSet: function (callback) {
callbackOnSet = callback;
},
SetUnits: function (unit) {
this.current = unit;
if (callbackOnSet)
callbackOnSet(unit);
},
FormatWithColon: function (f, bShowZero) {
assert(typeof f == "number");
var pre = "";
var strZero = (bShowZero ? "0" : "");
if (f < 0) {
f = -f;
pre = "-";
}
if (f == 0)
return strZero;
var units = Math.floor(f);
var str = "";
var subunits = Math.round((f - units) * this.ColonFactor());
if (subunits == 0)
str = "" + units;
else
str = "" + (units == 0 ? strZero : units) + ":" + subunits;
return pre + str;
},
ColonFactor: function () {
return (this.current == "d" ? 24 : 60);
},
TimeToUnits: function (time) {
var mult = MAP_UNITS[this.current];
assert(mult);
return time / mult;
},
UnitsToTime: function (units) {
var mult = MAP_UNITS[this.current];
assert(mult);
return units * mult;
},
GetUnit: function () {
assert(this.current);
return this.current;
},
GetSubUnit: function () {
if (this.current == this.minutes)
return "s";
if (this.current == this.hours)
return this.minutes;
if (this.current == this.days)
return this.hours;
assert(false);
return null; //happy lint
}
};
var g_bChromeStorage = (typeof (chrome) != "undefined" && chrome.storage && chrome.storage.local);
//use chrome.storage.local if available, else use localStorage
var g_storage = {
get: function (key, callback) { //callback(string or null)
if (g_bChromeStorage) {
chrome.storage.local.get(key, function (obj) {
var value = obj[key];
if (chrome.runtime.lastError)
console.log(chrome.runtime.lastError.message);
callback(value);
});
} else {
callback(localStorage.getItem(key));
}
},
//optional callback(string error or null)
set: function (key, strVal, callback) {
if (g_bChromeStorage) {
var pair = {};
pair[key] = strVal;
chrome.storage.local.set(pair, function () {
if (callback)
callback(chrome.runtime.lastError ? chrome.runtime.lastError.message : null);
});
} else {
localStorage.setItem(key, strVal);
if (callback)
callback(null);
}
},
remove: function (key, callback) { //optional callback(string error or null)
if (g_bChromeStorage) {
chrome.storage.local.remove(key, function () {
if (callback)
callback(chrome.runtime.lastError ? chrome.runtime.lastError.message : null);
});
} else {
localStorage.removeItem(key);
if (callback)
callback(null);
}
}
};
//information about what is being edited in the s/e card. can load/restore from storage per card
//NOTE: g_currentCardSEData.user can be "me", must be manually mapped to g_user.username
var g_currentCardSEData = {
loadFromStorage: function (idCard, callback) {
assert(idCard);
var key = this.keyStoragePrefix + idCard;
this.clearValues();
this.idCard = idCard;
var thisLocal = this;
g_storage.get(key, function (strVal) {
if (!strVal) {
callback();
return;
}
var value = JSON.parse(strVal);
assert(idCard == value.idCard);
if (thisLocal.idCard != idCard) {
//should never happen but handle possible rare timing if async storage
//does not callback
return;
}
thisLocal.msTime = value.msTime;
thisLocal.keyword = value.keyword;
thisLocal.user = value.user;
thisLocal.delta = value.delta;
thisLocal.s = value.s;
thisLocal.e = value.e;
thisLocal.note = value.note;
callback();
});
},
saveToStorage: function () {
assert(this.idCard);
var stringified = JSON.stringify({
idCard: this.idCard,
keyword: this.keyword,
user: this.user,
delta: this.delta,
s: this.s,
e: this.e,
note: this.note,
msTime: this.msTime
});
var key = this.keyStoragePrefix + this.idCard;
var thisLocal = this;
g_storage.set(key, stringified, function (strError) {
if (strError)
return;
thisLocal.strLastSaved = stringified;
});
},
setValues: function (idCard, keyword, user, delta, s, e, note) {
if (this.idCard == idCard &&
this.keyword == keyword &&
this.user == user &&
this.delta == delta &&
this.s == s &&
this.e == e &&
this.note == note) {
return;
}
this.idCard = idCard;
this.keyword = keyword;
this.user = user;
this.delta = delta;
this.s = s;
this.e = e;
this.note = note;
this.msTime = Date.now();
this.saveToStorage();
},
removeValue: function (idCardCur) {
if (!idCardCur)
idCardCur = this.idCard;
if (!idCardCur)
return;
var key = this.keyStoragePrefix + idCardCur;
g_storage.remove(key);
if (this.idCard == idCardCur)
this.clearValues();
},
//ALL BELOW ARE PRIVATE
clearValues: function () {
this.msTime = 0;
this.keyword = "";
this.user = "";
this.delta = "";
this.s = "";
this.e = "";
this.note = "";
//do not clear this.idCard, we want to leave it, as if the draft is all empty.
},
msTime: 0,
keyStoragePrefix: "cardSEDraft:",
strLastSaved: "", //note: because it contains the idCard, its OK to not clear this cache when the card changes
idCard: "",
keyword: "",
user: "", //note: can be "me". must be checked
delta: "",
s: "", //NOTE: s/e stored as strings. could contain ":"
e: "",
note: ""
};
//prepends [by user] [xd] [^etransfer from/to user] to comments, returns new string
function appendCommentBracketInfo(deltaParsed, comment, from, rgUsersProcess, iRowPush, bETransfer) {
var commentPush = comment;
var userCur = rgUsersProcess[iRowPush] || from;
var bSpecialETransferFrom = (bETransfer && iRowPush === 0);
var bSpecialETransferTo = (bETransfer && iRowPush === 1);
if (deltaParsed)
commentPush = "[" + deltaParsed + "d] " + commentPush;
if (userCur != from)
commentPush = "[by " + from + "] " + commentPush;
if (bSpecialETransferFrom) {
assert(rgUsersProcess[1]);
commentPush = g_prefixCommentTransferTo + rgUsersProcess[1] + "] " + commentPush;
} else if (bSpecialETransferTo) {
assert(rgUsersProcess[0]);
commentPush = g_prefixCommentTransferFrom + rgUsersProcess[0] + "] " + commentPush;
}
return commentPush;
}
var g_regexDashCleanup = /-/g;
function makeHistoryRowObject(dateNow, idCard, idBoard, strBoard, strCard, userCur, s, e, comment, idHistoryRowUse, keyword) {
//console.log(dateNow + " idCard:" + idCard + " idBoard:" + idBoard + " card:" + strCard + " board:" + strBoard);
var obj = {};
var userForId = replaceString(userCur, g_regexDashCleanup, '~'); //replace dashes from username. really should never happen since currently trello already strips dashes from trello username. see makeRowAtom
if (idHistoryRowUse) {
idHistoryRowUse = replaceString(idHistoryRowUse, g_regexDashCleanup, '~'); //replace dashes just in case. we use them to store more info later
obj.idHistory = 'idc' + idHistoryRowUse; //make up a unique 'notification' id across team users. start with string so it never confuses the spreadsheet, and we can also detect the ones with comment ids
}
else {
assert(IsStealthMode() || (s == 0 && e == 0)); //without an id, must be 0/0 to not mess up the totals on reset. plus commands fall here
obj.idHistory = 'id' + dateNow.getTime() + userForId; //make up a unique 'notification' id across team users. start with a string so it will never be confused by a number in the ss. user added to prevent multiple users with dup id
}
obj.idCard = idCard;
obj.idBoard = idBoard;
obj.keyword = keyword || null; //null will be handled later when is entered into history
var date = Math.floor(dateNow.getTime() / 1000); //seconds since 1970
obj.date = date; //review zig: warning! date should really be sDate as it measures seconds, not milliseconds.
obj.strBoard = strBoard;
obj.strCard = strCard;
obj.spent = s;
obj.est = e;
obj.user = userCur;
obj.week = getCurrentWeekNum(dateNow);
obj.month = getCurrentMonthFormatted(dateNow);
obj.comment = comment;
return obj;
}