-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathQQ.utils.js
150 lines (133 loc) · 5.13 KB
/
QQ.utils.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
/**
*
* @copyright 2013, 2014, QQ Trend Ltd.
* @license MIT
*/
/**
* This is kind of a factory for making date formatters.
*
* Note: generally better to use sugar.js for date formatting.
*
* @param A format string to use
* @return This returns an object, which has a format() function that is passed a datestamp
* @internal Adapted from http://stackoverflow.com/a/12213072/841830
* @internal An alternative is http://arshaw.com/xdate/ 7.2K (3.5KB gzipped).
* But it is slight overkill, as well really only need the .toString() formatting function.
*/
function DateFormatter(format) {
this.formatString = format;
var mthNames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
var dayNames = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
var zeroPad = function(number) { return ("0"+number).substr(-2,2); }
var dateMarkers = {
d:['getDate',function(v) { return zeroPad(v)}],
m:['getMonth',function(v) { return zeroPad(v+1)}],
n:['getMonth',function(v) { return mthNames[v]; }],
w:['getDay',function(v) { return dayNames[v]; }],
y:['getFullYear'],
H:['getHours',function(v) { return zeroPad(v)}],
M:['getMinutes',function(v) { return zeroPad(v)}],
S:['getSeconds',function(v) { return zeroPad(v)}],
i:['toISOString']
};
this.format = function(date) {
var dateTxt = this.formatString.replace(/%(.)/g, function(m, p) {
var rv = date[(dateMarkers[p])[0]]();
if ( dateMarkers[p][1] != null ) rv = dateMarkers[p][1](rv);
return rv;
});
return dateTxt;
}
}
var datestampFormat = new DateFormatter("%y-%m-%d"); //A global.
var YYYYMMDDFormat = new DateFormatter("%y%m%d"); //A global
var timeOfDayFormat = new DateFormatter("%H:%M"); //A global
//---------------------
//This is the JS complement of the back-end route classes.
/**
* You will call this when getting back an AJAX response from a route built
* on QQAPI\RouteWithList (or similar).
*
* NOTE: we assume error was not set; i.e. that it has already been handled.
*
* NOTE: it might throw. If it does, it is usually best to reload the top page of your
* web app (i.e. effectively delete all existing global data, and start over with fresh).
*
* @param list The array of data items sent by server. Each entry will be an array
* with action, name and data elements. The name/data parameters are passed
* to the helper functions. name is the global variable, and data is an
* associative array (i.e. Javascript object, to do key/value pairs, where the value
* is usually another object).
* @param data This is your top-level object holding all data from the server.
* If not given then it will default it to window.qqdata, and if that does not exist it will
* also create it.
*
* @internal We assume list will only ever have a few entries.
*
* @todo It might be useful to return an array of all objects that changed (that could
* then trigger UI updates)?
*
* @internal D and name are passed to each helper function, rather than D[name] as
* a single parameter, because JavaScript is "Call-by-sharing" rather than pass-by-reference.
* I.e. we sometimes need to assign to D[name].
*
* @todo Only one "." in a name supported currently. At some point it'd be good to make that generic, so any
* number can be supported.
*
* @internal We need to restore what `D` is on each pass, in case `name` on the previous iteration
* had a dot in it and D got changed.
*/
function processNewDataList(list, data){
if(!data){
if(!window.data)window.qqdata = {};
data = window.qqdata;
}
for(var ix=0;ix<list.length;++ix){
var D = data;
var name = list[ix].name;
var nix = name.indexOf(".");
if(nix>=0){ //handle name having "." in it
if(!D[name.substr(0,nix)])throw "Name prefix ("+name.substr(0,nix)+") in name ("+name+") should already exist.";
D=D[name.substr(0,nix)];
name = name.substr(nix+1);
}
if(!D[name])throw "Name("+name+") should already exist.";
switch(list[ix].action){
case "DP_replace":processNewDataReplace(D,name,list[ix].data);break;
case "DP_append":processNewDataAppend(D,name,list[ix].data);break; //Might throw
case "DP_update":processNewDataUpdate(D,name,list[ix].data);break; //Might throw
case "DP_insert":processNewDataInsert(D,name,list[ix].data);break;
default:throw "Unexpected action ("+action+")";break;
}
}
}
/**
* Simplest version: replace the whole collection.
*/
function processNewDataReplace(D,name,data){
D[name]=data;
}
/**
* Used to add additional entries, that must not already be there.
*/
function processNewDataAppend(D,name,data){
for(var key in data){
if(key in D[name])throw "key("+key+") already exists in "+name; //Not expected to exist.
D[name][key]=data[key];
}
}
/**
* The complement of processNewDataAppend: the key must already exist.
*/
function processNewDataUpdate(D,name,data){
for(var key in data){
if(key in D[name])D[name][key]=data[key];
else throw "key("+key+") should already exist in "+name+" but does not."; //Expected to exist.
}
}
/**
* Like append and replace: existing data replaced, new data created.
*/
function processNewDataInsert(D,name,data){
for(var key in data)D[name][key]=data[key];
}