Merge branch 'master' into urlstate
[mkws-moved-to-github.git] / src / mkws-filter.js
1 // Factory function for sets of filters.
2 function filterSet(team) {
3   var m_team = team;
4   var m_list = [];
5
6   var that = {};
7
8   that.toJSON = function() {
9     return mkws.$.toJSON(m_list);
10   };
11
12   that.add = function(filter) {
13     m_list.push(filter);
14   };
15
16   that.visitTargets = function(callback) {
17     for (var i in m_list) {
18       var filter = m_list[i];
19       if (filter.type === 'target') {
20         callback(filter.id, filter.name);
21       }
22     }
23   };
24
25   that.visitFields = function(callback) {
26     for (var i in m_list) {
27       var filter = m_list[i];
28       if (filter.type === 'field') {
29         callback(filter.field, filter.value);
30       }
31     }
32   };
33
34   that.visitCategories = function(callback) {
35     for (var i in m_list) {
36       var filter = m_list[i];
37       if (filter.type === 'category') {
38         callback(filter.id);
39       }
40     }
41   };
42
43   that.removeMatching = function(matchFn) {
44     var newList = [];
45     for (var i in m_list) {
46       var filter = m_list[i];
47       if (matchFn(filter)) {
48         m_team.info("removeMatching: removing filter " + mkws.$.toJSON(filter));
49       } else {
50         m_team.info("removeMatching: keeping filter " + mkws.$.toJSON(filter));
51         newList.push(filter);
52       }
53     }
54     m_list = newList;
55   };
56
57   // ### Surely the || in this function should be &&
58   that.targetFiltered = function(id) {
59     for (var i = 0; i < m_list.length; i++) {
60       if (m_list[i].type === 'target' ||
61           m_list[i].id === 'pz:id=' + id) {
62         return true;
63       }
64     }
65     return false;
66   };
67
68   that.pp2filter = function() {
69     var res = "";
70
71     that.visitTargets(function(id, name) {
72       if (res) res += ",";
73       if (id.match(/^[a-z:]+[=~]/)) {
74         m_team.info("filter '" + id + "' already begins with SETTING OP");
75       } else {
76         id = 'pz:id=' + id;
77       }
78       res += id;
79     });
80
81     return res;
82   };
83
84   that.pp2limit = function(initial) {
85     var res = initial || "";
86
87     that.visitFields(function(field, value) {
88       if (res) res += ",";
89       res += field + "=" + value.replace(/[\\|,]/g, '\\$&');
90     });
91     return res;
92   };
93
94   that.pp2catLimit = function() {
95     var res = "";
96
97     that.visitCategories(function(id) {
98       if (res) res += ",";
99       res += "category~" + id.replace(/[\\,]/g, '\\$&');
100     });
101     return res;
102   };
103
104   // Returns a hash of key=value pairs representing the filter-set
105   // These will become part of the URL-fragment representing the state
106   that.fragmentItems = function() {
107     var hash = {};
108
109     for (var i in m_list) {
110       var filter = m_list[i];
111       var type = filter.type;
112       if (type === 'target') {
113         hash['xt-' + filter.id] = filter.name;
114       } else if (type === 'field') {
115         // Ugly names, but we need to include the value because fields can be repeated
116         hash['xf-' + filter.field + '-' + filter.value] = 1;
117       } else if (type === 'category') {
118         hash['xc-' + filter.id] = 1;
119       } else {
120         alert("unsupported filter-type '" + type + "'");
121       }
122     }
123     
124     return hash;
125   };
126
127   that.deepCopy = function() {
128     var fs = filterSet(m_team);
129     fs._setList($.extend([], m_list));
130     return fs;
131   };
132
133   // Used only by clone()
134   that._setList = function(list) {
135     m_list = list;
136   };
137
138   return that;
139 }
140
141
142 // Factory functions for filters. These can be of several types.
143 function targetFilter(id, name) {
144   return {
145     type: 'target',
146     id: id,
147     name: name
148   };
149 }
150
151 function fieldFilter(field, value) {
152   return {
153     type: 'field',
154     field: field,
155     value: value
156   };
157 }
158
159 function categoryFilter(id) {
160   return {
161     type: 'category',
162     id: id
163   };
164 }