1 | /** |
---|
2 | * Set of thumbnails for each connection, indexed by ID. |
---|
3 | */ |
---|
4 | GuacamoleHistory = new (function() { |
---|
5 | |
---|
6 | /** |
---|
7 | * Reference to this GuacamoleHistory. |
---|
8 | */ |
---|
9 | var guac_history = this; |
---|
10 | |
---|
11 | /** |
---|
12 | * The number of entries to allow before removing old entries based on the |
---|
13 | * cutoff. |
---|
14 | */ |
---|
15 | var IDEAL_LENGTH = 6; |
---|
16 | |
---|
17 | /** |
---|
18 | * The maximum age of a history entry before it is removed, in |
---|
19 | * milliseconds. |
---|
20 | */ |
---|
21 | var CUTOFF_AGE = 900000; |
---|
22 | |
---|
23 | var history = {}; |
---|
24 | |
---|
25 | function truncate() { |
---|
26 | |
---|
27 | // Build list of entries |
---|
28 | var entries = []; |
---|
29 | for (var old_id in history) |
---|
30 | entries.push(history[old_id]); |
---|
31 | |
---|
32 | // Avoid history growth beyond defined number of entries |
---|
33 | if (entries.length > IDEAL_LENGTH) { |
---|
34 | |
---|
35 | // Sort list |
---|
36 | entries.sort(GuacamoleHistory.Entry.compare); |
---|
37 | |
---|
38 | // Remove entries until length is ideal or all are recent |
---|
39 | var now = new Date().getTime(); |
---|
40 | while (entries.length > IDEAL_LENGTH |
---|
41 | && now - entries[0].accessed > CUTOFF_AGE) { |
---|
42 | |
---|
43 | // Remove entry |
---|
44 | var removed = entries.shift(); |
---|
45 | delete history[removed.id]; |
---|
46 | |
---|
47 | } |
---|
48 | |
---|
49 | } |
---|
50 | |
---|
51 | } |
---|
52 | |
---|
53 | |
---|
54 | /** |
---|
55 | * Returns the URL for the thumbnail of the connection with the given ID, |
---|
56 | * or undefined if no thumbnail is associated with that connection. |
---|
57 | */ |
---|
58 | this.get = function(id) { |
---|
59 | return history[id] || new GuacamoleHistory.Entry(); |
---|
60 | }; |
---|
61 | |
---|
62 | /** |
---|
63 | * Updates the thumbnail and access time of the history entry for the |
---|
64 | * connection with the given ID. |
---|
65 | */ |
---|
66 | this.update = function(id, thumbnail) { |
---|
67 | |
---|
68 | // Create updated entry |
---|
69 | var entry = new GuacamoleHistory.Entry( |
---|
70 | id, |
---|
71 | thumbnail, |
---|
72 | new Date().getTime() |
---|
73 | ); |
---|
74 | |
---|
75 | // Store entry in history |
---|
76 | history[id] = entry; |
---|
77 | truncate(); |
---|
78 | |
---|
79 | // Save updated history |
---|
80 | localStorage.setItem("GUAC_HISTORY", JSON.stringify(history)); |
---|
81 | |
---|
82 | }; |
---|
83 | |
---|
84 | /** |
---|
85 | * Reloads all history data. |
---|
86 | */ |
---|
87 | this.reload = function() { |
---|
88 | |
---|
89 | // Get old and new for comparison |
---|
90 | var old_history = history; |
---|
91 | var new_history = JSON.parse(localStorage.getItem("GUAC_HISTORY") || "{}"); |
---|
92 | |
---|
93 | // Update history |
---|
94 | history = new_history; |
---|
95 | |
---|
96 | // Call onchange handler as necessary |
---|
97 | if (guac_history.onchange) { |
---|
98 | |
---|
99 | // Produce union of all known IDs |
---|
100 | var known_ids = {}; |
---|
101 | for (var new_id in new_history) known_ids[new_id] = true; |
---|
102 | for (var old_id in old_history) known_ids[old_id] = true; |
---|
103 | |
---|
104 | // For each known ID |
---|
105 | for (var id in known_ids) { |
---|
106 | |
---|
107 | // Get entries |
---|
108 | var old_entry = old_history[id]; |
---|
109 | var new_entry = new_history[id]; |
---|
110 | |
---|
111 | // Call handler for all changed |
---|
112 | if (!old_entry || !new_entry |
---|
113 | || old_entry.accessed != new_entry.accessed) |
---|
114 | guac_history.onchange(id, old_entry, new_entry); |
---|
115 | |
---|
116 | } |
---|
117 | |
---|
118 | } // end onchange |
---|
119 | |
---|
120 | }; |
---|
121 | |
---|
122 | /** |
---|
123 | * Event handler called whenever a history entry is changed. |
---|
124 | * |
---|
125 | * @event |
---|
126 | * @param {String} id The ID of the connection whose history entry is |
---|
127 | * changing. |
---|
128 | * @param {GuacamoleHistory.Entry} old_entry The old value of the entry, if |
---|
129 | * any. |
---|
130 | * @param {GuacamoleHistory.Entry} new_entry The new value of the entry, if |
---|
131 | * any. |
---|
132 | */ |
---|
133 | this.onchange = null; |
---|
134 | |
---|
135 | // Reload when modified |
---|
136 | window.addEventListener("storage", guac_history.reload, false); |
---|
137 | |
---|
138 | // Initial load |
---|
139 | guac_history.reload(); |
---|
140 | |
---|
141 | })(); |
---|
142 | |
---|
143 | /** |
---|
144 | * A single entry in the indexed connection usage history. |
---|
145 | * |
---|
146 | * @constructor |
---|
147 | * @param {String} id The ID of this connection. |
---|
148 | * @param {String} thumbnail The URL of the thumbnail to use to represent this |
---|
149 | * connection. |
---|
150 | * @param {Number} last_access The time this connection was last accessed, in |
---|
151 | * seconds. |
---|
152 | */ |
---|
153 | GuacamoleHistory.Entry = function(id, thumbnail, last_access) { |
---|
154 | |
---|
155 | /** |
---|
156 | * The ID of the connection associated with this history entry. |
---|
157 | */ |
---|
158 | this.id = id; |
---|
159 | |
---|
160 | /** |
---|
161 | * The thumbnail associated with the connection associated with this history |
---|
162 | * entry. |
---|
163 | */ |
---|
164 | this.thumbnail = thumbnail; |
---|
165 | |
---|
166 | /** |
---|
167 | * The time the connection associated with this entry was last accessed. |
---|
168 | */ |
---|
169 | this.accessed = last_access; |
---|
170 | |
---|
171 | }; |
---|
172 | |
---|
173 | GuacamoleHistory.Entry.compare = function(a, b) { |
---|
174 | return a.accessed - b.accessed; |
---|
175 | }; |
---|