parlement 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +709 -0
- data/COPYING +223 -0
- data/README +20 -0
- data/Rakefile +136 -0
- data/app/controllers/account_controller.rb +181 -0
- data/app/controllers/application.rb +30 -0
- data/app/controllers/elt_controller.rb +83 -0
- data/app/helpers/account_helper.rb +2 -0
- data/app/helpers/application_helper.rb +4 -0
- data/app/helpers/elt_helper.rb +37 -0
- data/app/helpers/live_tree.rb +238 -0
- data/app/helpers/mailman.rb +96 -0
- data/app/models/attachment.rb +4 -0
- data/app/models/elt.rb +17 -0
- data/app/models/mail.rb +4 -0
- data/app/models/notifier.rb +13 -0
- data/app/models/person.rb +9 -0
- data/app/models/user.rb +7 -0
- data/app/models/user_notify.rb +75 -0
- data/app/views/account/_help.rhtml +23 -0
- data/app/views/account/_login.rhtml +57 -0
- data/app/views/account/_show.rhtml +31 -0
- data/app/views/account/logout.rhtml +10 -0
- data/app/views/account/signup.rhtml +17 -0
- data/app/views/account/welcome.rhtml +13 -0
- data/app/views/elt/_elt.rhtml +105 -0
- data/app/views/elt/_form.rhtml +31 -0
- data/app/views/elt/_list.rhtml +28 -0
- data/app/views/elt/new.rhtml +102 -0
- data/app/views/elt/rss.rxml +31 -0
- data/app/views/elt/show.rhtml +46 -0
- data/app/views/elt/show_tree.rhtml +8 -0
- data/app/views/layouts/scaffold.rhtml +13 -0
- data/app/views/layouts/top.rhtml +45 -0
- data/app/views/notifier/changeEmail.rhtml +10 -0
- data/config/boot.rb +17 -0
- data/config/database.yml +82 -0
- data/config/environment.rb +92 -0
- data/config/environments/development.rb +17 -0
- data/config/environments/production.rb +17 -0
- data/config/environments/test.rb +17 -0
- data/config/environments/user_environment.rb +1 -0
- data/config/routes.rb +28 -0
- data/db/ROOT/CV.txt +166 -0
- data/db/ROOT/IP.txt +3 -0
- data/db/ROOT/parleR.txt +3 -0
- data/db/ROOT/parlement/security.txt +34 -0
- data/db/ROOT/parlement/test.txt +4 -0
- data/db/ROOT/parlement.txt +51 -0
- data/db/ROOT/perso.txt +215 -0
- data/db/schema.sql +127 -0
- data/lib/data_import.rb +54 -0
- data/lib/file_column.rb +263 -0
- data/lib/file_column_helper.rb +45 -0
- data/lib/localization.rb +88 -0
- data/lib/localizer.rb +88 -0
- data/lib/login_system.rb +87 -0
- data/lib/rails_file_column.rb +19 -0
- data/lib/user_system.rb +101 -0
- data/public/404.html +8 -0
- data/public/500.html +8 -0
- data/public/dispatch.cgi +10 -0
- data/public/dispatch.fcgi +24 -0
- data/public/dispatch.rb +10 -0
- data/public/engine_files/README +5 -0
- data/public/engine_files/login_engine/stylesheets/login_engine.css +81 -0
- data/public/favicon.ico +0 -0
- data/public/favicon.png +0 -0
- data/public/images/live_tree_branch_collapsed_icon.gif +0 -0
- data/public/images/live_tree_branch_expanded_icon.gif +0 -0
- data/public/images/live_tree_leaf_icon.gif +0 -0
- data/public/images/live_tree_loading_spinner.gif +0 -0
- data/public/images/webfeed.gif +0 -0
- data/public/javascripts/controls.js +721 -0
- data/public/javascripts/dragdrop.js +519 -0
- data/public/javascripts/effects.js +992 -0
- data/public/javascripts/live_tree.js +749 -0
- data/public/javascripts/prototype.js +1726 -0
- data/public/javascripts/scriptaculous.js +47 -0
- data/public/javascripts/slider.js +258 -0
- data/public/oldREADME +190 -0
- data/public/oldindex.html +78 -0
- data/public/robots.txt +1 -0
- data/public/stylesheets/default.css +238 -0
- data/public/stylesheets/live_tree.css +62 -0
- data/public/stylesheets/scaffold.css +74 -0
- data/script/about +3 -0
- data/script/benchmarker +19 -0
- data/script/breakpointer +3 -0
- data/script/console +3 -0
- data/script/create_db +7 -0
- data/script/destroy +3 -0
- data/script/generate +3 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/plugin +3 -0
- data/script/process/reaper +3 -0
- data/script/process/spawner +3 -0
- data/script/process/spinner +3 -0
- data/script/profiler +34 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/test/fixtures/attachments.yml +10 -0
- data/test/fixtures/elts.yml +15 -0
- data/test/fixtures/mails.yml +7 -0
- data/test/fixtures/people.yml +49 -0
- data/test/fixtures/users.yml +41 -0
- data/test/functional/account_controller_test.rb +239 -0
- data/test/functional/elt_controller_test.rb +18 -0
- data/test/mocks/test/time.rb +17 -0
- data/test/mocks/test/user_notify.rb +16 -0
- data/test/test_helper.rb +28 -0
- data/test/unit/attachment_test.rb +14 -0
- data/test/unit/elt_test.rb +14 -0
- data/test/unit/mail_test.rb +14 -0
- data/test/unit/notifier_test.rb +31 -0
- data/test/unit/person_test.rb +24 -0
- data/test/unit/user_test.rb +94 -0
- data/vendor/plugins/engines/CHANGELOG +7 -0
- data/vendor/plugins/engines/README +128 -0
- data/vendor/plugins/engines/init.rb +33 -0
- data/vendor/plugins/engines/lib/action_mailer_extensions.rb +160 -0
- data/vendor/plugins/engines/lib/action_view_extensions.rb +130 -0
- data/vendor/plugins/engines/lib/dependencies_extensions.rb +56 -0
- data/vendor/plugins/engines/lib/engines.rb +292 -0
- data/vendor/plugins/engines/lib/ruby_extensions.rb +127 -0
- data/vendor/plugins/engines/lib/testing_extensions.rb +33 -0
- data/vendor/plugins/engines/test/ruby_extensions_test.rb +94 -0
- data/vendor/plugins/login_engine/README +258 -0
- data/vendor/plugins/login_engine/app/controllers/user_controller.rb +248 -0
- data/vendor/plugins/login_engine/app/helpers/user_helper.rb +88 -0
- data/vendor/plugins/login_engine/app/models/user.rb +7 -0
- data/vendor/plugins/login_engine/app/models/user_notify.rb +75 -0
- data/vendor/plugins/login_engine/app/views/user/_edit.rhtml +11 -0
- data/vendor/plugins/login_engine/app/views/user/_password.rhtml +9 -0
- data/vendor/plugins/login_engine/app/views/user/change_password.rhtml +17 -0
- data/vendor/plugins/login_engine/app/views/user/edit.rhtml +23 -0
- data/vendor/plugins/login_engine/app/views/user/forgot_password.rhtml +18 -0
- data/vendor/plugins/login_engine/app/views/user/home.rhtml +7 -0
- data/vendor/plugins/login_engine/app/views/user/login.rhtml +17 -0
- data/vendor/plugins/login_engine/app/views/user/logout.rhtml +8 -0
- data/vendor/plugins/login_engine/app/views/user/signup.rhtml +17 -0
- data/vendor/plugins/login_engine/app/views/user_notify/change_password.rhtml +10 -0
- data/vendor/plugins/login_engine/app/views/user_notify/delete.rhtml +5 -0
- data/vendor/plugins/login_engine/app/views/user_notify/forgot_password.rhtml +11 -0
- data/vendor/plugins/login_engine/app/views/user_notify/pending_delete.rhtml +9 -0
- data/vendor/plugins/login_engine/app/views/user_notify/signup.rhtml +12 -0
- data/vendor/plugins/login_engine/db/schema.rb +25 -0
- data/vendor/plugins/login_engine/init_engine.rb +10 -0
- data/vendor/plugins/login_engine/lib/login_engine/authenticated_system.rb +107 -0
- data/vendor/plugins/login_engine/lib/login_engine/authenticated_user.rb +149 -0
- data/vendor/plugins/login_engine/lib/login_engine.rb +58 -0
- data/vendor/plugins/login_engine/public/stylesheets/login_engine.css +81 -0
- data/vendor/plugins/login_engine/tasks/tasks.rake +4 -0
- data/vendor/plugins/login_engine/test/fixtures/templates/users.yml +41 -0
- data/vendor/plugins/login_engine/test/fixtures/users.yml +41 -0
- data/vendor/plugins/login_engine/test/functional/user_controller_test.rb +533 -0
- data/vendor/plugins/login_engine/test/mocks/mail.rb +14 -0
- data/vendor/plugins/login_engine/test/mocks/time.rb +19 -0
- data/vendor/plugins/login_engine/test/test_helper.rb +15 -0
- data/vendor/plugins/login_engine/test/unit/user_test.rb +94 -0
- metadata +276 -0
@@ -0,0 +1,749 @@
|
|
1
|
+
// LiveTree, version: 0.1
|
2
|
+
//
|
3
|
+
// Home page: http://www.epiphyte.ca/code/live_tree.html
|
4
|
+
//
|
5
|
+
// Copyright (c) 2005 Emanuel Borsboom
|
6
|
+
//
|
7
|
+
// Permission is hereby granted, free of charge, to any person obtaining a
|
8
|
+
// copy of this software and associated documentation files (the
|
9
|
+
// "Software"), to deal in the Software without restriction, including
|
10
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
12
|
+
// persons to whom the Software is furnished to do so, subject to the
|
13
|
+
// following conditions:
|
14
|
+
//
|
15
|
+
// The above copyright notice and this permission notice shall be included
|
16
|
+
// in all copies or substantial portions of the Software.
|
17
|
+
//
|
18
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
19
|
+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
21
|
+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
22
|
+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
23
|
+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
24
|
+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
|
26
|
+
function LiveTree(id, options) {
|
27
|
+
this.id = id;
|
28
|
+
|
29
|
+
if (options == null) {
|
30
|
+
options = {};
|
31
|
+
}
|
32
|
+
|
33
|
+
this.dataUrl = options.dataUrl;
|
34
|
+
this.cssClass = options.cssClass;
|
35
|
+
this.cssStyle = options.cssStyle;
|
36
|
+
this.expandRootItem = (options.expandRootItem == null ? true : options.expandRootItem);
|
37
|
+
this.hideRootItem = (options.hideRootItem == null ? false : options.hideRootItem);
|
38
|
+
this.rootItemId = options.rootItemId;
|
39
|
+
this.expandItemOnClick = (options.expandItemOnClick == null ? true : options.expandItemOnClick);
|
40
|
+
this.initialData = options.initialData;
|
41
|
+
this.scroll = (options.scroll == null ? true : options.scroll);
|
42
|
+
this.preloadItems = (options.preloadItems == null ? true : options.preloadItems);
|
43
|
+
|
44
|
+
this.collapsedItemIconHtml = options.collapsedItemIconHtml;
|
45
|
+
this.expandedItemIconHtml = options.expandedItemIconHtml;
|
46
|
+
this.leafIconHtml = options.leafIconHtml;
|
47
|
+
this.loadingIconHtml = options.loadingIconHtml;
|
48
|
+
this.loadingTreeHtml = options.loadingTreeHtml;
|
49
|
+
this.searchingHtml = options.searchingHtml;
|
50
|
+
|
51
|
+
this.onClickItem = options.onClickItem;
|
52
|
+
this.allowClickBranch = (options.allowClickBranch == null ? true : options.allowClickBranch);
|
53
|
+
this.allowClickLeaf = (options.allowClickLeaf == null ? true : options.allowClickLeaf);
|
54
|
+
this.onExpandItem = options.onExpandItem;
|
55
|
+
this.onCollapseItem = options.onCollapseItem;
|
56
|
+
this.onLoadItem = options.onLoadItem;
|
57
|
+
|
58
|
+
this._root = {};
|
59
|
+
this._itemsIndex = {};
|
60
|
+
this._activeItemId = null;
|
61
|
+
this._scrollToItemIdOnLoad = null;
|
62
|
+
this._scrollToItemMustBeExpanded = false;
|
63
|
+
this._searchCount = 0;
|
64
|
+
this._preloadCount = 0;
|
65
|
+
this._updateItemDisplay = null;
|
66
|
+
}
|
67
|
+
|
68
|
+
LiveTree.prototype._markItemForUpdateDisplay = function (item) {
|
69
|
+
var tree = this;
|
70
|
+
// This is not very intelligent yet... basically if only one item needs to be updated, that's fine, otherwise the whole tree is updated.
|
71
|
+
if (tree._updateItemDisplay == null) {
|
72
|
+
tree._updateItemDisplay = item;
|
73
|
+
} else if (tree._updateItemDisplay != item) {
|
74
|
+
tree._updateItemDisplay = tree._root;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
LiveTree.prototype._getClass = function (suffix) {
|
79
|
+
if (suffix != "") {
|
80
|
+
suffix = "_" + suffix;
|
81
|
+
}
|
82
|
+
result = 'live_tree' + suffix;
|
83
|
+
if (this.cssClass != null) {
|
84
|
+
result += ' ' + this.cssClass + suffix;
|
85
|
+
}
|
86
|
+
return result;
|
87
|
+
}
|
88
|
+
|
89
|
+
LiveTree.prototype._getCollapsedItemIconHtml = function () {
|
90
|
+
if (this.collapsedItemIconHtml != null) {
|
91
|
+
return this.collapsedItemIconHtml;
|
92
|
+
} else {
|
93
|
+
return '<img src="/images/live_tree_branch_collapsed_icon.gif" alt=">" width="9" height="9" class="' + this._getClass("item_icon") + '" />';
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
LiveTree.prototype._getExpandedItemIconHtml = function () {
|
98
|
+
if (this.expandedItemIconHtml != null) {
|
99
|
+
return this.expandedItemIconHtml;
|
100
|
+
} else {
|
101
|
+
return '<img src="/images/live_tree_branch_expanded_icon.gif" alt="v" width="9" height="9" class="' + this._getClass("item_icon") + '" />';
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
LiveTree.prototype._getLeafIconHtml = function () {
|
106
|
+
if (this.leafIconHtml != null) {
|
107
|
+
return this.leafIconHtml;
|
108
|
+
} else {
|
109
|
+
return '<img src="/images/live_tree_leaf_icon.gif" alt=" " width="9" height="9" class="' + this._getClass("item_icon") + '" />';
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
LiveTree.prototype._getLoadingIconHtml = function () {
|
114
|
+
if (this.loadingIconHtml != null) {
|
115
|
+
return this.loadingIconHtml;
|
116
|
+
} else {
|
117
|
+
return '<img src="/images/live_tree_loading_spinner.gif" alt="[loading]" width="10" height="10" class="' + this._getClass("loading_icon") + '" />';
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
LiveTree.prototype._getLoadingTreeHtml = function () {
|
122
|
+
if (this.loadingTreeHtml != null) {
|
123
|
+
return this.loadingTreeHtml;
|
124
|
+
} else {
|
125
|
+
return '<span class="' + this._getClass("loading_tree") + '">' + this._getLoadingIconHtml() + 'Loading tree data…</span>';
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
LiveTree.prototype._getSearchingHtml = function () {
|
130
|
+
if (this.searchingHtml != null) {
|
131
|
+
return this.searchingHtml;
|
132
|
+
} else {
|
133
|
+
return '<div class="' + this._getClass("searching") + '">' + this._getLoadingIconHtml() + 'Searching for item…</div>';
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
LiveTree.prototype._addItem = function (item, parent) {
|
138
|
+
// If this item ID was already loaded, copy its status from the old data
|
139
|
+
var oldItem = this._itemsIndex[item.id];
|
140
|
+
if (oldItem != null) {
|
141
|
+
item.isLoading = oldItem.isLoading;
|
142
|
+
item.isLoadingBackground = oldItem.isLoadingBackground;
|
143
|
+
item.isExpanded = oldItem.isExpanded;
|
144
|
+
}
|
145
|
+
this._itemsIndex[item.id] = item;
|
146
|
+
|
147
|
+
// Add some extra properties
|
148
|
+
item.isLeaf = !(item.children == null || item.children.length > 0);
|
149
|
+
item.isLoaded = item.children != null;
|
150
|
+
item.parent = parent;
|
151
|
+
|
152
|
+
// Replace or add this item in the parent's list of children
|
153
|
+
if (parent.children == null) {
|
154
|
+
parent.children = [item];
|
155
|
+
} else {
|
156
|
+
var found = false;
|
157
|
+
for (var i = 0; i < parent.children.length; i++) {
|
158
|
+
if (parent.children[i].id == item.id) {
|
159
|
+
parent.children[i] = item;
|
160
|
+
found = true;
|
161
|
+
break;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
if (!found) {
|
165
|
+
parent.children[parent.children.length] = item;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
// Now add the item's children as well
|
170
|
+
if (item.children != null) {
|
171
|
+
for (var i = 0; i < item.children.length; i++) {
|
172
|
+
this._addItem(item.children[i], item);
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
LiveTree.prototype._startPreloads = function (item) {
|
178
|
+
var tree = this;
|
179
|
+
if (!tree.preloadItems || tree._preloadCount > 0) {
|
180
|
+
return false;
|
181
|
+
}
|
182
|
+
if (item == null) {
|
183
|
+
item = tree._root;
|
184
|
+
}
|
185
|
+
//alert("startPreloads " + item.id);
|
186
|
+
if (!item.isExpanded || item.isLoading) {
|
187
|
+
return false;
|
188
|
+
}
|
189
|
+
var tailBranch = true;
|
190
|
+
for (var i = 0; i < item.children.length; i++) {
|
191
|
+
var child = item.children[i];
|
192
|
+
if (!child.isLeaf && ( child.isLoaded || child.isLoading )) {
|
193
|
+
tailBranch = false;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
var doLoad = false;
|
197
|
+
if (tailBranch) {
|
198
|
+
for (var i = 0; i < item.children.length; i++) {
|
199
|
+
var child = item.children[i];
|
200
|
+
if (!child.isLeaf) {
|
201
|
+
if (!child.isLoaded && !child.isLoading) {
|
202
|
+
//alert("setting loading for " + child.id);
|
203
|
+
doLoad = true;
|
204
|
+
child.isLoading = true;
|
205
|
+
child.isLoadingBackground = true;
|
206
|
+
}
|
207
|
+
}
|
208
|
+
}
|
209
|
+
}
|
210
|
+
var didLoad = false;
|
211
|
+
if (doLoad) {
|
212
|
+
//alert("preloading children of " + item.id);
|
213
|
+
tree._preloadCount++;
|
214
|
+
tree._requestItem(item.id, 3, tree._onPreloadItemReceived.bind(tree));
|
215
|
+
tree._markItemForUpdateDisplay(item);
|
216
|
+
didLoad = true;
|
217
|
+
} else {
|
218
|
+
for (var i = 0; i < item.children.length; i++) {
|
219
|
+
var child = item.children[i];
|
220
|
+
if (!child.isLeaf && child.isLoaded) {
|
221
|
+
if (tree._startPreloads(child)) {
|
222
|
+
didLoad = true;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
return didLoad;
|
229
|
+
}
|
230
|
+
|
231
|
+
LiveTree.prototype._handleReceivedItem = function (item, requestOptions) {
|
232
|
+
var tree = this;
|
233
|
+
|
234
|
+
// Find item's parent
|
235
|
+
var parent = null;
|
236
|
+
if (requestOptions.includeParents) {
|
237
|
+
// The response includes the desired item's parents, but we don't want to over-write
|
238
|
+
// data that is already there (since it may include other children deeper down), so
|
239
|
+
// go down the tree until we find an item that hasn't been loaded before (or we get to the
|
240
|
+
// requested item)
|
241
|
+
var newParent = tree._getItem(item.id).parent;
|
242
|
+
while (true) {
|
243
|
+
// since we included parents, there should only be a single child with children, so find that one
|
244
|
+
var child = null;
|
245
|
+
for (var i = 0; i < item.children.length; i++) {
|
246
|
+
if (item.children[i].children != null && item.children[i].children.length > 0) {
|
247
|
+
if (child != null) {
|
248
|
+
alert("LiveTree error: didn't expect multiple children with children while iterating through parents");
|
249
|
+
return;
|
250
|
+
}
|
251
|
+
child = item.children[i];
|
252
|
+
}
|
253
|
+
}
|
254
|
+
if (child == null || tree._getItem(child.id) == null) {
|
255
|
+
break;
|
256
|
+
}
|
257
|
+
newParent = item;
|
258
|
+
item = child;
|
259
|
+
}
|
260
|
+
parent = tree._getItem(newParent.id);
|
261
|
+
} else {
|
262
|
+
// First, check if root is the parent
|
263
|
+
if (tree._root.children == null) {
|
264
|
+
// ... which is always the case if the root has no children, since that means nothing has been loaded yet
|
265
|
+
parent = tree._root;
|
266
|
+
} else {
|
267
|
+
for (var i = 0; i < tree._root.children.length; i++) {
|
268
|
+
if (item.id == tree._root.children[i].id) {
|
269
|
+
parent = tree._root;
|
270
|
+
break;
|
271
|
+
}
|
272
|
+
}
|
273
|
+
}
|
274
|
+
// Otherwise, it must have been loaded before, so get the old parent
|
275
|
+
if (parent == null) {
|
276
|
+
var oldItem = tree._itemsIndex[item.id];
|
277
|
+
if (oldItem == null) {
|
278
|
+
alert("LiveTree error: attempt to load item of unknown parentage");
|
279
|
+
return false;
|
280
|
+
}
|
281
|
+
parent = oldItem.parent;
|
282
|
+
}
|
283
|
+
}
|
284
|
+
|
285
|
+
// Now add the item to its parent
|
286
|
+
tree._addItem(item, parent);
|
287
|
+
//alert(ekb_inspect(tree._root));
|
288
|
+
tree._markItemForUpdateDisplay(parent);
|
289
|
+
|
290
|
+
if (tree.onLoadItem != null) {
|
291
|
+
tree.onLoadItem(item);
|
292
|
+
}
|
293
|
+
return true;
|
294
|
+
}
|
295
|
+
|
296
|
+
LiveTree.prototype._onItemResponse = function (request, onItemCallback, requestOptions) {
|
297
|
+
var tree = this;
|
298
|
+
if (requestOptions.includeParents) {
|
299
|
+
tree._searchCount--;
|
300
|
+
}
|
301
|
+
var item;
|
302
|
+
try {
|
303
|
+
eval("item = " + request.responseText);
|
304
|
+
} catch (e) {
|
305
|
+
alert("LiveTree error: bad items data from server: " + e);
|
306
|
+
return;
|
307
|
+
}
|
308
|
+
var handled = tree._handleReceivedItem(item, requestOptions);
|
309
|
+
if (handled) {
|
310
|
+
onItemCallback(item, requestOptions);
|
311
|
+
}
|
312
|
+
}
|
313
|
+
|
314
|
+
LiveTree.prototype._requestItem = function (itemId, depth, onItemCallback, options) {
|
315
|
+
var tree = this;
|
316
|
+
if (options == null) {
|
317
|
+
options = {};
|
318
|
+
}
|
319
|
+
var url = tree.dataUrl;
|
320
|
+
if (url == null) {
|
321
|
+
alert("LiveTree error: no data URL provided");
|
322
|
+
return false;
|
323
|
+
}
|
324
|
+
var requestOptions = new Object();
|
325
|
+
var delim = "?";
|
326
|
+
if (itemId != null) {
|
327
|
+
requestOptions.itemId = itemId;
|
328
|
+
url += delim + "item_id=" + itemId;
|
329
|
+
delim = "&";
|
330
|
+
}
|
331
|
+
if (depth != null) {
|
332
|
+
requestOptions.depth = depth;
|
333
|
+
url += delim + "depth=" + depth;
|
334
|
+
delim = "&";
|
335
|
+
}
|
336
|
+
if (options.includeParents) {
|
337
|
+
requestOptions.includeParents = true;
|
338
|
+
requestOptions.rootItemId = tree.rootItemId;
|
339
|
+
url += delim + "include_parents=1&root_item_id=" + tree.rootItemId;
|
340
|
+
tree._searchCount++;
|
341
|
+
}
|
342
|
+
new Ajax.Request(url, {onComplete:function (request) { tree._onItemResponse(request, onItemCallback, requestOptions) }, evalScripts:true, asynchronous:true});
|
343
|
+
return true;
|
344
|
+
}
|
345
|
+
|
346
|
+
LiveTree.prototype._onExpandItemReceived = function (item, requestOptions) {
|
347
|
+
var tree = this;
|
348
|
+
item.isLoading = false;
|
349
|
+
tree._startPreloads();
|
350
|
+
tree._updateDisplay();
|
351
|
+
}
|
352
|
+
|
353
|
+
LiveTree.prototype._onPreloadItemReceived = function (item, requestOptions) {
|
354
|
+
var tree = this;
|
355
|
+
tree._preloadCount--;
|
356
|
+
for (var i = 0; i < item.children.length; i++) {
|
357
|
+
item.children[i].isLoading = false;
|
358
|
+
}
|
359
|
+
tree._markItemForUpdateDisplay(item);
|
360
|
+
tree._startPreloads();
|
361
|
+
tree._updateDisplay();
|
362
|
+
}
|
363
|
+
|
364
|
+
LiveTree.prototype._onClickExpand = function (item) {
|
365
|
+
var tree = this;
|
366
|
+
var expanded = tree._expandItem(item);
|
367
|
+
tree._updateDisplay();
|
368
|
+
if (expanded) {
|
369
|
+
tree.scrollToItem(item.id);
|
370
|
+
if (item.isLoading) {
|
371
|
+
tree._scrollToItemIdOnLoad = item.id;
|
372
|
+
tree._scrollToItemMustBeExpanded = true;
|
373
|
+
}
|
374
|
+
if (tree.onExpandItem != null) {
|
375
|
+
tree.onExpandItem(item);
|
376
|
+
}
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
LiveTree.prototype._onClickCollapse = function (item) {
|
381
|
+
var tree = this;
|
382
|
+
if (!item.isExpanded) {
|
383
|
+
return;
|
384
|
+
}
|
385
|
+
item.isExpanded = false;
|
386
|
+
tree._markItemForUpdateDisplay(item);
|
387
|
+
tree._updateDisplay();
|
388
|
+
if (tree.onCollapseItem != null) {
|
389
|
+
tree.onCollapseItem(item);
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
LiveTree.prototype._onClickItem = function (item) {
|
394
|
+
var tree = this;
|
395
|
+
if (tree.expandItemOnClick && !item.isExpanded && !item.isLeaf) {
|
396
|
+
tree._onClickExpand(item);
|
397
|
+
}
|
398
|
+
if (tree.onClickItem != null && ((tree.allowClickLeaf && item.isLeaf) || (tree.allowClickBranch && !item.isLeaf))) {
|
399
|
+
tree.onClickItem(item);
|
400
|
+
}
|
401
|
+
tree._updateDisplay();
|
402
|
+
}
|
403
|
+
|
404
|
+
LiveTree.prototype._getItem = function (itemId) {
|
405
|
+
return this._itemsIndex[itemId];
|
406
|
+
}
|
407
|
+
|
408
|
+
LiveTree.prototype._getItemElement = function (itemId) {
|
409
|
+
return $(this.id + "_item_" + itemId);
|
410
|
+
}
|
411
|
+
|
412
|
+
LiveTree.prototype._displayItem = function (item, isRoot) {
|
413
|
+
var tree = this;
|
414
|
+
var elem;
|
415
|
+
if (isRoot) {
|
416
|
+
elem = $(tree.id + "_root");
|
417
|
+
} else {
|
418
|
+
elem = tree._getItemElement(item.id);
|
419
|
+
}
|
420
|
+
var html = '';
|
421
|
+
if (!isRoot) {
|
422
|
+
if (!item.isLeaf) {
|
423
|
+
if (item.isExpanded) {
|
424
|
+
html += '<a href="#" id="' + tree.id + '_branch_collapse_link_' + item.id + '" class="' + this._getClass("branch_collapse_link") + '">'; {
|
425
|
+
html += tree._getExpandedItemIconHtml();
|
426
|
+
} html += '</a>';
|
427
|
+
} else {
|
428
|
+
html += '<a href="#" id="' + tree.id + '_branch_expand_link_' + item.id + '" class="' + this._getClass("branch_expand_link") + '">'; {
|
429
|
+
html += tree._getCollapsedItemIconHtml();
|
430
|
+
} html += '</a>';
|
431
|
+
}
|
432
|
+
if (item.isLoading && !item.isLoadingBackground) {
|
433
|
+
html += tree._getLoadingIconHtml();
|
434
|
+
}
|
435
|
+
} else {
|
436
|
+
html += tree._getLeafIconHtml();
|
437
|
+
}
|
438
|
+
var item_link_exists = false;
|
439
|
+
var extraNameClass = "";
|
440
|
+
if (item.id == tree._activeItemId) {
|
441
|
+
extraNameClass = " " + this._getClass("active_item_name");
|
442
|
+
}
|
443
|
+
var name_html = '<span id="' + tree.id + '_item_name_' + item.id + '" class="' + this._getClass("item_name") + extraNameClass + '">' + item.name + '</span>';
|
444
|
+
if ((tree.onClickItem != null && ((tree.allowClickLeaf && item.isLeaf) || (tree.allowClickBranch && !item.isLeaf))) ||
|
445
|
+
(tree.expandItemOnClick && !item.isLeaf && !item.isExpanded)) {
|
446
|
+
name_html = '<a href="#" id="' + tree.id + '_item_link_' + item.id + '" class="' + this._getClass("item_link") + '">' + name_html + '</a>';
|
447
|
+
item_link_exists = true;
|
448
|
+
}
|
449
|
+
//name_html = "(" + item.id + ") " + name_html;
|
450
|
+
html += name_html;
|
451
|
+
//if (item.isLoading && item.isLoadingBackground) {
|
452
|
+
// html += " " + tree._getLoadingIconHtml();
|
453
|
+
//}
|
454
|
+
}
|
455
|
+
if (item.isExpanded && item.children != null) {
|
456
|
+
var childrenListId;
|
457
|
+
if (isRoot) {
|
458
|
+
childrenListId = tree.id + '_children_list_root';
|
459
|
+
} else {
|
460
|
+
childrenListId = tree.id + '_children_list_' + item.id;
|
461
|
+
}
|
462
|
+
if (!isRoot) {
|
463
|
+
html += '<ul id="' + childrenListId + '" class="' + this._getClass("branch") + '">';
|
464
|
+
}
|
465
|
+
for (var i = 0; i < item.children.length; i++) {
|
466
|
+
var child = item.children[i];
|
467
|
+
html += '<li id="' + tree.id + '_item_' + child.id + '" class="' + this._getClass("item") + '"></li>';
|
468
|
+
}
|
469
|
+
if (!isRoot) {
|
470
|
+
html += '</ul>';
|
471
|
+
}
|
472
|
+
}
|
473
|
+
elem.innerHTML = html;
|
474
|
+
if (!isRoot) {
|
475
|
+
if (!item.isLeaf) {
|
476
|
+
if (item.isExpanded) {
|
477
|
+
$(tree.id + '_branch_collapse_link_' + item.id).onclick = function () { tree._onClickCollapse(item); return false }
|
478
|
+
} else {
|
479
|
+
$(tree.id + '_branch_expand_link_' + item.id).onclick = function () { tree._onClickExpand(item); return false }
|
480
|
+
}
|
481
|
+
}
|
482
|
+
if (item_link_exists) {
|
483
|
+
$(tree.id + '_item_link_' + item.id).onclick = function() { tree._onClickItem(item); return false }
|
484
|
+
}
|
485
|
+
}
|
486
|
+
if (item.isExpanded && item.children != null) {
|
487
|
+
for (var i = 0; i < item.children.length; i++) {
|
488
|
+
tree._displayItem(item.children[i], false);
|
489
|
+
}
|
490
|
+
}
|
491
|
+
}
|
492
|
+
|
493
|
+
LiveTree.prototype._checkScrollOnLoad = function () {
|
494
|
+
var tree = this;
|
495
|
+
if (tree._scrollToItemIdOnLoad == null) {
|
496
|
+
return;
|
497
|
+
}
|
498
|
+
var item = tree._itemsIndex[tree._scrollToItemIdOnLoad];
|
499
|
+
if (item == null) {
|
500
|
+
return;
|
501
|
+
}
|
502
|
+
if (tree._scrollToItemMustBeExpanded) {
|
503
|
+
if (item.isLoaded) {
|
504
|
+
// The user may have collapsed the item while it was loading, so only scroll to it if it's still expanded.
|
505
|
+
if (item.isExpanded) {
|
506
|
+
tree.scrollToItem(item.id);
|
507
|
+
}
|
508
|
+
tree._scrollToItemIdOnLoad = null;
|
509
|
+
}
|
510
|
+
} else {
|
511
|
+
tree.scrollToItem(item.id);
|
512
|
+
tree._scrollToItemIdOnLoad = null;
|
513
|
+
}
|
514
|
+
}
|
515
|
+
|
516
|
+
LiveTree.prototype._updateDisplay = function () {
|
517
|
+
var tree = this;
|
518
|
+
if (tree._searchCount > 0) {
|
519
|
+
Element.show(tree.id + "_searching");
|
520
|
+
} else {
|
521
|
+
Element.hide(tree.id + "_searching");
|
522
|
+
}
|
523
|
+
var updateItem = tree._updateItemDisplay;
|
524
|
+
if (updateItem != null) {
|
525
|
+
tree._updateItemDisplay = null;
|
526
|
+
var html = "";
|
527
|
+
var isRoot = false;
|
528
|
+
if (updateItem == tree._root || (tree.hideRootItem && updateItem == tree._root.children[0])) {
|
529
|
+
if (tree.hideRootItem) {
|
530
|
+
updateItem = tree._root.children[0];
|
531
|
+
}
|
532
|
+
isRoot = true;
|
533
|
+
}
|
534
|
+
tree._displayItem(updateItem, isRoot);
|
535
|
+
}
|
536
|
+
tree._checkScrollOnLoad();
|
537
|
+
}
|
538
|
+
|
539
|
+
LiveTree.prototype._onInitialItemReceived = function () {
|
540
|
+
var tree = this;
|
541
|
+
this.rootItemId = tree._root.children[0].id;
|
542
|
+
if (tree.hideRootItem) {
|
543
|
+
//tree._root = tree._root.children[0];
|
544
|
+
tree._expandItem(tree._root.children[0]);
|
545
|
+
} else if (tree.expandRootItem) {
|
546
|
+
tree._expandItem(tree._root.children[0]);
|
547
|
+
}
|
548
|
+
tree._root.isExpanded = true;
|
549
|
+
tree._markItemForUpdateDisplay(tree._root);
|
550
|
+
tree._startPreloads();
|
551
|
+
}
|
552
|
+
|
553
|
+
LiveTree.prototype._getElementPosition = function (destinationLink) {
|
554
|
+
// borrowed from http://www.sitepoint.com/print/scroll-smoothly-javascript
|
555
|
+
var destx = destinationLink.offsetLeft;
|
556
|
+
var desty = destinationLink.offsetTop;
|
557
|
+
var thisNode = destinationLink;
|
558
|
+
while (thisNode.offsetParent &&
|
559
|
+
(thisNode.offsetParent != document.body)) {
|
560
|
+
thisNode = thisNode.offsetParent;
|
561
|
+
destx += thisNode.offsetLeft;
|
562
|
+
desty += thisNode.offsetTop;
|
563
|
+
}
|
564
|
+
return { x: destx, y: desty }
|
565
|
+
}
|
566
|
+
|
567
|
+
LiveTree.prototype._scrollTo = function (top) {
|
568
|
+
var tree = this;
|
569
|
+
if (!tree.scroll) {
|
570
|
+
return;
|
571
|
+
}
|
572
|
+
var containerElem = $(tree.id);
|
573
|
+
containerElem.scrollTop = top;
|
574
|
+
}
|
575
|
+
|
576
|
+
LiveTree.prototype.scrollToItem = function (itemId) {
|
577
|
+
var tree = this;
|
578
|
+
if (!tree.scroll) {
|
579
|
+
return;
|
580
|
+
}
|
581
|
+
var itemElem = tree._getItemElement(itemId);
|
582
|
+
if (itemElem == null) {
|
583
|
+
return;
|
584
|
+
}
|
585
|
+
var containerElem = $(tree.id);
|
586
|
+
var itemPos = tree._getElementPosition(itemElem);
|
587
|
+
var containerPos = tree._getElementPosition(containerElem);
|
588
|
+
var itemTop = itemPos.y - containerPos.y;
|
589
|
+
var containerHeight = containerElem.offsetHeight - 35; //HACK: adjust for space used by scrollbars and other decoration
|
590
|
+
if (itemTop + itemElem.offsetHeight > containerElem.scrollTop + containerHeight ||
|
591
|
+
itemTop < containerElem.scrollTop) {
|
592
|
+
// item is currently not entirely visible
|
593
|
+
if (itemElem.offsetHeight > containerHeight) {
|
594
|
+
// item is too big to fit, so scroll to the top
|
595
|
+
tree._scrollTo(itemTop);
|
596
|
+
} else {
|
597
|
+
if (itemTop < containerElem.scrollTop + containerHeight) {
|
598
|
+
// item is partially onscreen (the top is showing), so put whole item at bottom
|
599
|
+
tree._scrollTo(itemTop + itemElem.offsetHeight - containerHeight);
|
600
|
+
} else {
|
601
|
+
// item is entirely offscreen, so center it
|
602
|
+
tree._scrollTo(itemTop - containerHeight/2 + itemElem.offsetHeight/2);
|
603
|
+
}
|
604
|
+
}
|
605
|
+
}
|
606
|
+
tree._scrollToItemOnLoad = null;
|
607
|
+
}
|
608
|
+
|
609
|
+
LiveTree.prototype._expandItem = function (item) {
|
610
|
+
var tree = this;
|
611
|
+
|
612
|
+
// Make sure all item's parents are expanded as well
|
613
|
+
var didExpand = false;
|
614
|
+
var parent = item.parent;
|
615
|
+
while (parent != tree._root && parent != null) {
|
616
|
+
if (!parent.isExpanded) {
|
617
|
+
parent.isExpanded = true;
|
618
|
+
tree._markItemForUpdateDisplay(parent);
|
619
|
+
didExpand = true;
|
620
|
+
}
|
621
|
+
parent = parent.parent;
|
622
|
+
}
|
623
|
+
|
624
|
+
// Expand the selected item
|
625
|
+
var needToLoad = false;
|
626
|
+
if (!item.isExpanded) {
|
627
|
+
needToLoad = (item.children == null && !item.isLoading);
|
628
|
+
if (needToLoad) {
|
629
|
+
item.isLoading = true;
|
630
|
+
}
|
631
|
+
item.isLoadingBackground = false;
|
632
|
+
item.isExpanded = true;
|
633
|
+
tree._markItemForUpdateDisplay(item);
|
634
|
+
didExpand = true;
|
635
|
+
}
|
636
|
+
|
637
|
+
// If the item has not loaded, load it now
|
638
|
+
if (needToLoad) {
|
639
|
+
tree._requestItem(item.id, 2, tree._onExpandItemReceived.bind(tree));
|
640
|
+
}
|
641
|
+
|
642
|
+
tree._startPreloads();
|
643
|
+
return didExpand;
|
644
|
+
}
|
645
|
+
|
646
|
+
LiveTree.prototype._onExpandItemParentsReceived = function (item, requestOptions) {
|
647
|
+
var tree = this;
|
648
|
+
var requestedItem = tree._getItem(requestOptions.itemId);
|
649
|
+
this._expandItem(requestedItem);
|
650
|
+
tree._startPreloads();
|
651
|
+
tree._updateDisplay();
|
652
|
+
}
|
653
|
+
|
654
|
+
LiveTree.prototype.expandItem = function (itemId) {
|
655
|
+
var tree = this;
|
656
|
+
var item = tree._getItem(itemId);
|
657
|
+
var search = false;
|
658
|
+
if (item == null) {
|
659
|
+
tree._requestItem(itemId, 2, tree._onExpandItemParentsReceived.bind(tree), { includeParents: true });
|
660
|
+
search = true;
|
661
|
+
} else {
|
662
|
+
this._expandItem(this._itemsIndex[itemId]);
|
663
|
+
}
|
664
|
+
tree._updateDisplay();
|
665
|
+
if (search) {
|
666
|
+
tree._scrollTo(0);
|
667
|
+
tree._scrollToItemIdOnLoad = itemId;
|
668
|
+
tree._scrollToItemMustBeExpanded = false;
|
669
|
+
} else {
|
670
|
+
tree.scrollToItem(itemId);
|
671
|
+
}
|
672
|
+
}
|
673
|
+
|
674
|
+
LiveTree.prototype._onExpandParentsOfItemReceived = function (item, requestOptions) {
|
675
|
+
var tree = this;
|
676
|
+
var requestedItem = tree._getItem(requestOptions.itemId);
|
677
|
+
tree._expandItem(requestedItem.parent);
|
678
|
+
tree._startPreloads();
|
679
|
+
tree._updateDisplay();
|
680
|
+
}
|
681
|
+
|
682
|
+
LiveTree.prototype.expandParentsOfItem = function (itemId) {
|
683
|
+
var tree = this;
|
684
|
+
var item = tree._getItem(itemId);
|
685
|
+
var search = false;
|
686
|
+
if (item == null) {
|
687
|
+
tree._requestItem(itemId, 1, tree._onExpandParentsOfItemReceived.bind(tree), { includeParents: true });
|
688
|
+
search = true;
|
689
|
+
} else {
|
690
|
+
tree._expandItem(item.parent);
|
691
|
+
}
|
692
|
+
tree._updateDisplay();
|
693
|
+
if (search) {
|
694
|
+
tree._scrollTo(0);
|
695
|
+
tree._scrollToItemIdOnLoad = itemId;
|
696
|
+
tree._scrollToItemMustBeExpanded = false;
|
697
|
+
} else {
|
698
|
+
tree.scrollToItem(itemId);
|
699
|
+
}
|
700
|
+
}
|
701
|
+
|
702
|
+
LiveTree.prototype.activateItem = function (itemId) {
|
703
|
+
var tree = this;
|
704
|
+
// un-highlight the old active item
|
705
|
+
var oldElem = $(tree.id + '_item_name_' + tree._activeItemId);
|
706
|
+
if (oldElem != null) {
|
707
|
+
oldElem.className = tree._getClass("item_name");
|
708
|
+
}
|
709
|
+
// highlight the new active item
|
710
|
+
var elem = $(tree.id + '_item_name_' + itemId);
|
711
|
+
if (elem != null) {
|
712
|
+
elem.className = tree._getClass("item_name") + " " + tree._getClass("active_item_name");
|
713
|
+
}
|
714
|
+
tree._activeItemId = itemId;
|
715
|
+
tree.scrollToItem(itemId);
|
716
|
+
}
|
717
|
+
|
718
|
+
LiveTree.prototype.getHtml = function() {
|
719
|
+
var tree = this;
|
720
|
+
var html = '';
|
721
|
+
html += '<div id="' + tree.id + '" class="' + tree._getClass("") + '"';
|
722
|
+
if (tree.cssStyle != null) {
|
723
|
+
html += ' style="' + tree.cssStyle + '"';
|
724
|
+
}
|
725
|
+
html += '>';
|
726
|
+
html += '<div id="' + tree.id + '_searching" style="display:none">' + tree._getSearchingHtml() + '</div>';
|
727
|
+
html += '<ul id="' + tree.id + '_root" class="' + tree._getClass("root") + '">' + tree._getLoadingTreeHtml() + '</ul>'
|
728
|
+
html += '</div>';
|
729
|
+
return html;
|
730
|
+
}
|
731
|
+
|
732
|
+
LiveTree.prototype.start = function() {
|
733
|
+
var tree = this;
|
734
|
+
if (tree.initialData != null) {
|
735
|
+
var handled = tree._handleReceivedItem(tree.initialData, {});
|
736
|
+
if (handled) {
|
737
|
+
tree._onInitialItemReceived(tree.initialData);
|
738
|
+
}
|
739
|
+
tree._updateDisplay();
|
740
|
+
} else {
|
741
|
+
tree._requestItem(tree.rootItemId, tree.expandRootItem || tree.hideRootItem ? 2 : 1, tree._onInitialItemReceived.bind(tree));
|
742
|
+
}
|
743
|
+
}
|
744
|
+
|
745
|
+
LiveTree.prototype.render = function () {
|
746
|
+
var tree = this;
|
747
|
+
document.write(tree.getHtml());
|
748
|
+
tree.start();
|
749
|
+
}
|