/[drupal]/contributions/modules/hierarchical_select/hierarchical_select_cache.js
ViewVC logotype

Contents of /contributions/modules/hierarchical_select/hierarchical_select_cache.js

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.8 - (show annotations) (download) (as text)
Sun Nov 30 01:56:35 2008 UTC (11 months, 4 weeks ago) by wimleers
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +2 -2 lines
File MIME type: text/javascript
Fixed #321180: Regressions in cache system
1 // $Id: hierarchical_select_cache.js,v 1.7 2008/09/17 21:36:53 wimleers Exp $
2
3 /**
4 * @file
5 * Cache system for Hierarchical Select.
6 * This cache system takes advantage of the HTML 5 client-side database
7 * storage specification to reduce the number of queries to the server. A lazy
8 * loading strategy is used.
9 */
10
11
12 /**
13 * Note: this cache system can be replaced by another one, as long as you
14 * provide the following methods:
15 * - initialize()
16 * - status()
17 * - load()
18 * - sync()
19 * - updateHierarchicalSelect()
20 *
21 * TODO: better documentation
22 */
23
24 (function ($) {
25
26 Drupal.HierarchicalSelect.cache = {};
27
28 Drupal.HierarchicalSelect.cache.initialize = function() {
29 try {
30 if (window.openDatabase) {
31 this.db = openDatabase("Hierarchical Select", "3.x", "Hierarchical Select cache", 200000);
32
33 this.db
34 // Create the housekeeping table if it doesn't exist yet.
35 .transaction(function(tx) {
36 tx.executeSql("SELECT COUNT(*) FROM hierarchical_select", [], null, function(tx, error) {
37 tx.executeSql("CREATE TABLE hierarchical_select (table_name TEXT UNIQUE, expires REAL)", []);
38 console.log("Created housekeeping table.");
39 });
40 })
41 // Empty tables that have expired, based on the information in the
42 // housekeeping table.
43 .transaction(function(tx) {
44 tx.executeSql("SELECT table_name FROM hierarchical_select WHERE expires < ?", [ new Date().getTime() ], function(tx, resultSet) {
45 for (var i = 0; i < resultSet.rows.length; i++) {
46 var row = resultSet.rows.item(i);
47 var newExpiresTimestamp = new Date().getTime() + 86400;
48
49 tx.executeSql("DELETE * FROM " + row.table_name);
50 tx.executeSql("UPDATE hierarchical_select SET expires = ? WHERE table_name = ?", [ newExpiresTimestamp, row.table_name ]);
51
52 console.log("Table "+ row.table_name +" was expired: emptied it. Will expire again in "+ (newExpiresTimestamp - new Date().getTime()) / 3600 +" hours.");
53 }
54 });
55 });
56 }
57 else {
58 this.db = false;
59 }
60 }
61 catch(err) { }
62 };
63
64 Drupal.HierarchicalSelect.cache.status = function() {
65 return Drupal.HierarchicalSelect.cache.db !== false;
66 };
67
68 Drupal.HierarchicalSelect.cache.table = function(hsid) {
69 return Drupal.settings.HierarchicalSelect.settings[hsid].cacheId;
70 };
71
72 Drupal.HierarchicalSelect.cache.load = function(hsid) {
73 // If necessary, create the cache table for the given Hierarchical Select.
74 Drupal.HierarchicalSelect.cache.db.transaction(function(tx) {
75 var table = Drupal.HierarchicalSelect.cache.table(hsid);
76
77 tx.executeSql("SELECT value FROM "+ table, [], function(tx, resultSet) {
78 console.log("" + resultSet.rows.length + " cached items in the " + table + " table.");
79 }, function(tx, error) {
80 var expiresTimestamp = new Date().getTime() + 86400;
81
82 tx.executeSql("CREATE TABLE "+ table +" (parent REAL, value REAL UNIQUE, label REAL, weight REAL)");
83 tx.executeSql("INSERT INTO hierarchical_select (table_name, expires) VALUES (?, ?)", [ table, expiresTimestamp ]);
84
85 console.log("Created table "+ table +", will expire in "+ (expiresTimestamp - new Date().getTime()) / 3600 +" hours.");
86 });
87 });
88 };
89
90 Drupal.HierarchicalSelect.cache.insertOnDuplicateKeyUpdate = function(table, row) {
91 // console.log("storing: value: "+ row.value +", label: "+ row.label +", parent: "+ row.parent +", weight: "+ row.weight);
92 Drupal.HierarchicalSelect.cache.db.transaction(function(tx) {
93 tx.executeSql("INSERT INTO "+ table +" (parent, value, label, weight) VALUES (?, ?, ?, ?)", [ row.parent, row.value, row.label, row.weight ], null, function(tx, error) {
94 // console.log("UPDATING value: "+ row.value +", label: "+ row.label +", parent: "+ row.parent +", weight: "+ row.weight);
95 tx.executeSql("UPDATE "+ table +" SET parent = ?, label = ?, weight = ? WHERE value = ?", [ row.parent, row.label, row.weight, row.value ], null, function(tx, error) {
96 // console.log("sql error: " + error.message);
97 });
98 });
99 });
100 };
101
102 Drupal.HierarchicalSelect.cache.sync = function(hsid, info) {
103 var table = Drupal.HierarchicalSelect.cache.table(hsid);
104 for (var id in info) {
105 var closure = function(_info, id) {
106 Drupal.HierarchicalSelect.cache.insertOnDuplicateKeyUpdate(table, _info[id]);
107 } (info, id);
108 }
109 };
110
111 Drupal.HierarchicalSelect.cache.hasChildren = function(hsid, value, successCallback, failCallback) {
112 var table = Drupal.HierarchicalSelect.cache.table(hsid);
113 Drupal.HierarchicalSelect.cache.db.transaction(function(tx) {
114 tx.executeSql("SELECT * FROM "+ table +" WHERE parent = ?", [ value ], function(tx, resultSet) {
115 if (resultSet.rows.length > 0) {
116 successCallback();
117 }
118 else {
119 failCallback();
120 }
121 });
122 });
123 };
124
125 Drupal.HierarchicalSelect.cache.getSubLevels = function(hsid, value, callback, previousSubLevels) {
126 var table = Drupal.HierarchicalSelect.cache.table(hsid);
127
128 var subLevels = new Array();
129 if (previousSubLevels != undefined) {
130 subLevels = previousSubLevels;
131 }
132
133 Drupal.HierarchicalSelect.cache.db.transaction(function(tx) {
134 tx.executeSql("SELECT value, label FROM "+ table +" WHERE parent = ? ORDER BY weight", [ value ], function(tx, resultSet) {
135 var numChildren = resultSet.rows.length;
136
137 // If there's only one child, check if it has the dummy "<value>-has-no-children" value.
138 if (numChildren == 1) {
139 var valueOfFirstRow = String(resultSet.rows.item(0).value);
140 var isDummy = valueOfFirstRow.match(/^.*-has-no-children$/);
141 }
142
143 // Only pass the children if there are any (and not a fake one either).
144 if (numChildren && !isDummy) {
145 var level = new Array();
146 for (var i = 0; i < resultSet.rows.length; i++) {
147 var row = resultSet.rows.item(i);
148 level[i] = { 'value' : row.value, 'label' : row.label };
149 console.log("child of "+ value +": ("+ row.value +", "+ row.label +")");
150 }
151
152 subLevels.push(level);
153
154 Drupal.HierarchicalSelect.cache.getSubLevels(hsid, level[0].value, callback, subLevels);
155 }
156 else {
157 if (subLevels.length > 0) {
158 callback(subLevels);
159 }
160 else {
161 callback(false);
162 }
163 }
164 });
165 });
166 };
167
168 Drupal.HierarchicalSelect.cache.createAndUpdateSelects = function(hsid, subLevels, lastUnchanged) {
169 // Remove all levels below the level in which a value was selected, if they
170 // exist.
171 // Note: the root level can never change because of this!
172 $('#hierarchical-select-'+ hsid +'-wrapper .hierarchical-select .selects select').slice(lastUnchanged).remove();
173
174 // Create the new sublevels, by cloning the root level and then modifying
175 // that clone.
176 var $rootSelect = $('#hierarchical-select-'+ hsid +'-wrapper .hierarchical-select .selects select:first');
177 for (var depth in subLevels) {
178 var optionElements = $.map(subLevels[depth], function(item) { return '<option value="'+ item.value +'">'+ item.label +'</option>'; });
179
180 var level = parseInt(lastUnchanged) + parseInt(depth);
181
182 $('#hierarchical-select-'+ hsid +'-wrapper .hierarchical-select .selects select:last').after(
183 $rootSelect.clone()
184 // Update the name attribute.
185 .attr('name', $rootSelect.attr('name').replace(/(.*)\d+\]$/, "$1"+ level +"]"))
186 // Update the id attribute.
187 .attr('id', $rootSelect.attr('id').replace(/(.*-hierarchical-select-selects-)\d+/, "$1"+ level))
188 // Remove the existing options and set the new ones.
189 .empty().append(optionElements.join(''))
190 );
191 }
192 };
193
194 Drupal.HierarchicalSelect.cache.updateHierarchicalSelect = function(hsid, value, settings, lastUnchanged, ajaxOptions) {
195 // If the selected value has children
196 Drupal.HierarchicalSelect.cache.hasChildren(hsid, value, function() {
197 console.log("Cache hit.");
198 Drupal.HierarchicalSelect.cache.getSubLevels(hsid, value, function(subLevels) {
199 Drupal.HierarchicalSelect.preUpdateAnimations(hsid, 'update-hierarchical-select', lastUnchanged, function() {
200 if (subLevels !== false) {
201 Drupal.HierarchicalSelect.cache.createAndUpdateSelects(hsid, subLevels, lastUnchanged);
202 }
203 else {
204 // Nothing must happen: the user selected a value that doesn't
205 // have any subLevels.
206 $('#hierarchical-select-' + hsid + '-wrapper .hierarchical-select .selects select').slice(lastUnchanged).remove();
207 }
208
209 Drupal.HierarchicalSelect.postUpdateAnimations(hsid, 'update-hierarchical-select', lastUnchanged, function() {
210 // Reattach the bindings.
211 Drupal.HierarchicalSelect.attachBindings(hsid);
212
213 Drupal.HierarchicalSelect.triggerEvents(hsid, 'update-hierarchical-select', settings);
214
215 // The selection of this hierarchical select has changed!
216 Drupal.HierarchicalSelect.triggerEvents(hsid, 'change-hierarchical-select', settings);
217 });
218 });
219 });
220 }, function() {
221 // This item was not yet requested before, so we still have to perform
222 // the dynamic form submit.
223 console.log("Cache miss. Querying the server.");
224 Drupal.HierarchicalSelect.preUpdateAnimations(hsid, 'update-hierarchical-select', lastUnchanged, function() {
225 $.ajax(ajaxOptions);
226 });
227 });
228 };
229
230 })(jQuery);

  ViewVC Help
Powered by ViewVC 1.1.2