radiant-fabulator_exhibit-extension 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +9 -0
- data/README.markdown +3 -0
- data/Rakefile +3 -2
- data/VERSION +1 -1
- data/app/models/fabulator_exhibit.rb +4 -0
- data/fabulator_exhibit_extension.rb +11 -2
- data/lib/tasks/fabulator_exhibit_extension_tasks.rake +30 -0
- data/public/javascripts/fabulator/exhibit/data.js +745 -0
- data/public/javascripts/fabulator/exhibit/exhibit.js +160 -0
- data/public/javascripts/fabulator/exhibit/expressions.js +1028 -0
- data/public/javascripts/fabulator/exhibit/facets.js +579 -0
- data/public/javascripts/fabulator/exhibit/views.js +457 -0
- data/public/stylesheets/fabulator/exhibit/exhibit.css +109 -0
- metadata +49 -10
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
=== 0.0.2 2010-10-26
|
2
|
+
* 1 major enhancement:
|
3
|
+
* Provides javascript/css for implementing Exhibit views in HTML
|
4
|
+
|
5
|
+
* 3 minor enhancement:
|
6
|
+
* Explicit dependance on UUID gem
|
7
|
+
* Requires fabulator-exhibit 0.0.4
|
8
|
+
* Requires Radiant fabulator extension 0.0.6
|
9
|
+
|
1
10
|
=== 0.0.1 2010-08-10
|
2
11
|
|
3
12
|
* 1 major enhancement:
|
data/README.markdown
CHANGED
@@ -16,6 +16,9 @@ libraries:
|
|
16
16
|
|
17
17
|
== LICENSE:
|
18
18
|
|
19
|
+
N.B.: The JavaScript libraries in this distribution are under a separate
|
20
|
+
license. See the JavaScript files for more information.
|
21
|
+
|
19
22
|
Copyright (c) 2009-2010 Texas A&M University
|
20
23
|
|
21
24
|
Permission is hereby granted, free of charge, to any person obtaining
|
data/Rakefile
CHANGED
@@ -7,9 +7,10 @@ begin
|
|
7
7
|
gem.email = "jgsmith@tamu.edu"
|
8
8
|
gem.homepage = "http://github.com/jgsmith/radiant-fabulator-exhibit"
|
9
9
|
gem.authors = ["James Smith"]
|
10
|
-
gem.add_dependency('radiant-fabulator-extension', '>= 0.0.
|
11
|
-
gem.add_dependency('fabulator-exhibit', '>= 0.0.
|
10
|
+
gem.add_dependency('radiant-fabulator-extension', '>= 0.0.6')
|
11
|
+
gem.add_dependency('fabulator-exhibit', '>= 0.0.4')
|
12
12
|
gem.add_dependency('json', '>= 1.4.3')
|
13
|
+
gem.add_dependency('uuid', '>= 2.3.1')
|
13
14
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
15
|
end
|
15
16
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
@@ -2,6 +2,10 @@ class FabulatorExhibit < ActiveRecord::Base
|
|
2
2
|
validates_presence_of :name
|
3
3
|
validates_uniqueness_of :name
|
4
4
|
|
5
|
+
has_many :fabulator_exhibit_types
|
6
|
+
has_many :fabulator_exhibit_items
|
7
|
+
has_many :fabulator_exhibit_properties
|
8
|
+
|
5
9
|
belongs_to :updated_by, :class_name => 'User'
|
6
10
|
belongs_to :created_by, :class_name => 'User'
|
7
11
|
end
|
@@ -2,7 +2,7 @@ require 'fabulator/exhibit'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
class FabulatorExhibitExtension < Radiant::Extension
|
5
|
-
version "
|
5
|
+
version "0.0.2"
|
6
6
|
description "Exhibit extension to the Fabulator extension"
|
7
7
|
url "http://github.com/jgsmith/radiant-fabulator-exhibit"
|
8
8
|
|
@@ -16,6 +16,13 @@ class FabulatorExhibitExtension < Radiant::Extension
|
|
16
16
|
def activate
|
17
17
|
#raise FabulatorExhibitExtension::MissingRequirement.new('FabulatorExtension must be installed and loaded first.') unless defined?(FabulatorExtension)
|
18
18
|
|
19
|
+
%w{exhibit.js data.js expressions.js views.js facets.js}.each do |s|
|
20
|
+
FabulatorExtension.scripts << "fabulator/exhibit/#{s}"
|
21
|
+
end
|
22
|
+
#FabulatorExtension.scripts << 'fabulator/exhibit/exhibit.js'
|
23
|
+
#FabulatorExtension.scripts << 'fabulator/exhibit/exhibit-expressions.js'
|
24
|
+
FabulatorExtension.css << 'fabulator/exhibit/exhibit.css'
|
25
|
+
|
19
26
|
tab 'Fabulator' do
|
20
27
|
add_item("Exhibit Databases", "/admin/fabulator/exhibits")
|
21
28
|
end
|
@@ -26,7 +33,9 @@ class FabulatorExhibitExtension < Radiant::Extension
|
|
26
33
|
end
|
27
34
|
admin.exhibits = load_default_fabulator_exhibit_regions
|
28
35
|
|
29
|
-
|
36
|
+
## TODO: better database so we can have multiple applications accessing
|
37
|
+
## the same database at the same time
|
38
|
+
Fabulator::Exhibit::Lib.class_eval do
|
30
39
|
def self.fetch_database(nom)
|
31
40
|
db = FabulatorExhibit.find(:first, :conditions => [ 'name = ?', nom ])
|
32
41
|
if db.nil?
|
@@ -0,0 +1,30 @@
|
|
1
|
+
namespace :radiant do
|
2
|
+
namespace :extensions do
|
3
|
+
namespace :fabulator_exhibit do
|
4
|
+
|
5
|
+
desc "Runs the migration for the Fabulator Exhibit extension"
|
6
|
+
task :migrate => :environment do
|
7
|
+
require 'radiant/extension_migrator'
|
8
|
+
if ENV["VERSION"]
|
9
|
+
FabulatorExhibitExtension.migrator.migrate(ENV["VERSION"].to_i)
|
10
|
+
Rake::Task['db:schema:dump'].invoke
|
11
|
+
else
|
12
|
+
FabulatorExhibitExtension.migrator.migrate
|
13
|
+
Rake::Task['db:schema:dump'].invoke
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Copies public assets of the Fabulator Exhibit extenion to the instance public/ directory."
|
18
|
+
task :update => :environment do
|
19
|
+
is_svn_or_dir = proc { |path| path =~ /\.svn/ || File.directory?(path) }
|
20
|
+
Dir[FabulatorExhibitExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
|
21
|
+
path = file.sub(FabulatorExhibitExtension.root, '')
|
22
|
+
directory = File.dirname(path)
|
23
|
+
puts "Copying #{path}..."
|
24
|
+
mkdir_p RAILS_ROOT + directory, :verbose => false
|
25
|
+
cp file, RAILS_ROOT + path, :verbose => false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,745 @@
|
|
1
|
+
/*
|
2
|
+
* (c) Copyright Texas A&M University 2010. All rights reserved.
|
3
|
+
*
|
4
|
+
* Portions of this code are copied from The SIMILE Project:
|
5
|
+
* (c) Copyright The SIMILE Project 2006. All rights reserved.
|
6
|
+
*
|
7
|
+
* Redistribution and use in source and binary forms, with or without
|
8
|
+
* modification, are permitted provided that the following conditions
|
9
|
+
* are met:
|
10
|
+
*
|
11
|
+
* 1. Redistributions of source code must retain the above copyright
|
12
|
+
* notice, this list of conditions and the following disclaimer.
|
13
|
+
*
|
14
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
15
|
+
* notice, this list of conditions and the following disclaimer in the
|
16
|
+
* documentation and/or other materials provided with the distribution.
|
17
|
+
*
|
18
|
+
* 3. The name of the author may not be used to endorse or promote products
|
19
|
+
* derived from this software without specific prior written permission.
|
20
|
+
*
|
21
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
22
|
+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
23
|
+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
24
|
+
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
25
|
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
26
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
27
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
28
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
29
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
30
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
*
|
32
|
+
*/
|
33
|
+
|
34
|
+
Fabulator.namespace('Exhibit');
|
35
|
+
|
36
|
+
(function($, Exhibit) {
|
37
|
+
|
38
|
+
var sources = { };
|
39
|
+
|
40
|
+
Exhibit.DataView = function(options) {
|
41
|
+
var that = { },
|
42
|
+
set = Exhibit.Set();
|
43
|
+
that.options = options;
|
44
|
+
|
45
|
+
that.events = { };
|
46
|
+
that.events.onModelChange = fluid.event.getEventFirer();
|
47
|
+
|
48
|
+
that.events.onFilterItem = fluid.event.getEventFirer(false, true);
|
49
|
+
|
50
|
+
that.registerFilter = function(ob) {
|
51
|
+
that.events.onFilterItem.addListener(function(s,i) { return ob.eventFilterItem(s,i); });
|
52
|
+
that.events.onModelChange.addListener(function(m) { ob.eventModelChange(m) });
|
53
|
+
ob.events.onFilterChange.addListener(that.eventFilterChange);
|
54
|
+
};
|
55
|
+
|
56
|
+
that.items = set.items;
|
57
|
+
|
58
|
+
that.size = set.size;
|
59
|
+
|
60
|
+
that.filterItems = function() {
|
61
|
+
var id, fres, ids;
|
62
|
+
|
63
|
+
set = Exhibit.Set();
|
64
|
+
|
65
|
+
that.items = set.items;
|
66
|
+
|
67
|
+
that.size = set.size;
|
68
|
+
|
69
|
+
ids = that.dataSource.items();
|
70
|
+
|
71
|
+
$(ids).each(function(idx, id) {
|
72
|
+
/* do filtering here */
|
73
|
+
// id = ids[id];
|
74
|
+
fres = that.events.onFilterItem.fire(that.dataSource, id);
|
75
|
+
if(fres !== false) {
|
76
|
+
set.add(id);
|
77
|
+
}
|
78
|
+
});
|
79
|
+
};
|
80
|
+
|
81
|
+
that.eventModelChange = function(model) {
|
82
|
+
var id;
|
83
|
+
|
84
|
+
that.filterItems();
|
85
|
+
|
86
|
+
that.events.onModelChange.fire(that);
|
87
|
+
};
|
88
|
+
|
89
|
+
that.eventFilterChange = function() {
|
90
|
+
var id;
|
91
|
+
|
92
|
+
that.filterItems();
|
93
|
+
|
94
|
+
that.events.onModelChange.fire(that);
|
95
|
+
};
|
96
|
+
|
97
|
+
that.getItem = function(id) {
|
98
|
+
return that.dataSource.getItem(id);
|
99
|
+
};
|
100
|
+
|
101
|
+
var createInputElement = function(inputType) {
|
102
|
+
var div = document.createElement("div");
|
103
|
+
div.innerHTML = "<input type='" + inputType + "' />";
|
104
|
+
return div.firstChild;
|
105
|
+
};
|
106
|
+
|
107
|
+
var createDOMFromTemplate = function(rootID, templateNode, result, parentElmt) {
|
108
|
+
var node, elmt, tag, attribute, value, v, n, i, items;
|
109
|
+
|
110
|
+
if(templateNode == null) {
|
111
|
+
return null;
|
112
|
+
}
|
113
|
+
else if( typeof templateNode != "object" ) {
|
114
|
+
node = document.createTextNode(templateNode);
|
115
|
+
if( parentElmt != null ) {
|
116
|
+
parentElmt.appendChild(node);
|
117
|
+
}
|
118
|
+
return node;
|
119
|
+
}
|
120
|
+
else {
|
121
|
+
elmt = null;
|
122
|
+
if( "tag" in templateNode ) {
|
123
|
+
tag = templateNode.tag;
|
124
|
+
if( parentElmt != null ) {
|
125
|
+
if( tag == "tr" ) {
|
126
|
+
elmt = parentElmt.insertRow(parentElmt.rows.length);
|
127
|
+
}
|
128
|
+
else if( tag == "td" ) {
|
129
|
+
elmt == parentElmt.insertCell(parentElmt.cells.length);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
if( elmt == null ) {
|
133
|
+
elmt = tag == "input" ?
|
134
|
+
createInputElement(templateNode.type) :
|
135
|
+
document.createElement(tag);
|
136
|
+
if( parentElmt != null ) {
|
137
|
+
parentElmt.appendChild(elmt);
|
138
|
+
}
|
139
|
+
}
|
140
|
+
}
|
141
|
+
else {
|
142
|
+
elmt = templateNode.elmt;
|
143
|
+
if( parentElmt != null ) {
|
144
|
+
parentElmt.appendChild(elmt);
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
for(attribute in templateNode) {
|
149
|
+
value = templateNode[attribute];
|
150
|
+
|
151
|
+
if( attribute == "field" ) {
|
152
|
+
result[value] = elmt;
|
153
|
+
}
|
154
|
+
else if( attribute == "className" ) {
|
155
|
+
elmt.className = value;
|
156
|
+
}
|
157
|
+
else if( attribute == "id" ) {
|
158
|
+
elmt.id = id;
|
159
|
+
}
|
160
|
+
else if( attribute == "title" ) {
|
161
|
+
elmt.title = value;
|
162
|
+
}
|
163
|
+
else if( attribute == "type" && elm.tagName == "input") {
|
164
|
+
// do nothing
|
165
|
+
}
|
166
|
+
else if( attribute == "style" ) {
|
167
|
+
for( n in value ) {
|
168
|
+
v = value[n];
|
169
|
+
elmt.style[n] = v;
|
170
|
+
}
|
171
|
+
}
|
172
|
+
else if( attribute == "content" ) {
|
173
|
+
if( value != null ) {
|
174
|
+
items = value.evaluateOneItem(rootID, that.dataSource);
|
175
|
+
if( items.values.size() > 1 ) {
|
176
|
+
// we have a list of items
|
177
|
+
}
|
178
|
+
else if( items.values.size() == 1 ) {
|
179
|
+
elmt.innerText = (items.values.items())[0];
|
180
|
+
}
|
181
|
+
}
|
182
|
+
}
|
183
|
+
else if( attribute == "subcontentAttributes" ) {
|
184
|
+
if( value != null ) {
|
185
|
+
$(value).each(function(idx, info) {
|
186
|
+
var setting = "";
|
187
|
+
|
188
|
+
$(info.expression).each(function(idx, e) {
|
189
|
+
var r;
|
190
|
+
if(typeof(e) == "string") {
|
191
|
+
setting += e;
|
192
|
+
}
|
193
|
+
else {
|
194
|
+
r = e.evaluateOneItem(rootID, that.dataSource);
|
195
|
+
setting += (r.values.items()).join("");
|
196
|
+
}
|
197
|
+
});
|
198
|
+
$(elmt).attr(info.name, setting);
|
199
|
+
});
|
200
|
+
}
|
201
|
+
}
|
202
|
+
else if( attribute == "children" ) {
|
203
|
+
if( value != null ) {
|
204
|
+
for(i = 0, n = value.length; i < n; i++) {
|
205
|
+
createDOMFromTemplate(rootID, value[i], result, elmt);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
}
|
209
|
+
else if( attribute != "tag" && attribute != "elmt" ) {
|
210
|
+
elmt.setAttribute(attribute, value);
|
211
|
+
}
|
212
|
+
}
|
213
|
+
return elmt;
|
214
|
+
}
|
215
|
+
};
|
216
|
+
|
217
|
+
that.renderTemplate = function(rootID, template) {
|
218
|
+
var result = {};
|
219
|
+
result.elmt = createDOMFromTemplate(rootID, template, result, null);
|
220
|
+
|
221
|
+
return result;
|
222
|
+
};
|
223
|
+
|
224
|
+
that.dataSource = Exhibit.DataSource({ source: options.source });
|
225
|
+
that.dataSource.events.onModelChange.addListener(that.eventModelChange);
|
226
|
+
|
227
|
+
return that;
|
228
|
+
};
|
229
|
+
|
230
|
+
Exhibit.Set = function(values) {
|
231
|
+
var that = { },
|
232
|
+
items = { },
|
233
|
+
count = 0,
|
234
|
+
recalc_items = true,
|
235
|
+
items_list = new Array();
|
236
|
+
|
237
|
+
that.isSet = true;
|
238
|
+
|
239
|
+
that.items = function() {
|
240
|
+
if(recalc_items) {
|
241
|
+
items_list = new Array();
|
242
|
+
for(i in items) {
|
243
|
+
if(typeof(i) == "string" && items[i] == true) {
|
244
|
+
items_list.push(i);
|
245
|
+
}
|
246
|
+
}
|
247
|
+
}
|
248
|
+
return items_list;
|
249
|
+
}
|
250
|
+
|
251
|
+
that.add = function(item) {
|
252
|
+
if( !(item in items) ) {
|
253
|
+
items[item] = true;
|
254
|
+
recalc_items = true;
|
255
|
+
count += 1;
|
256
|
+
}
|
257
|
+
};
|
258
|
+
|
259
|
+
that.remove = function(item) {
|
260
|
+
if( item in items ) {
|
261
|
+
delete items[item];
|
262
|
+
recalc_items = true;
|
263
|
+
count -= 1;
|
264
|
+
}
|
265
|
+
};
|
266
|
+
|
267
|
+
that.visit = function(fn) {
|
268
|
+
var o;
|
269
|
+
for(o in items) {
|
270
|
+
if(fn(o) === true) {
|
271
|
+
break;
|
272
|
+
}
|
273
|
+
}
|
274
|
+
};
|
275
|
+
|
276
|
+
that.contains = function(o) {
|
277
|
+
return( o in items );
|
278
|
+
};
|
279
|
+
|
280
|
+
that.size = function() {
|
281
|
+
if( recalc_items ) {
|
282
|
+
return that.items().length;
|
283
|
+
}
|
284
|
+
else {
|
285
|
+
return items_list.length;
|
286
|
+
}
|
287
|
+
};
|
288
|
+
|
289
|
+
if(values instanceof Array) {
|
290
|
+
$(values).each(function(idx, i) {
|
291
|
+
that.add(i);
|
292
|
+
});
|
293
|
+
}
|
294
|
+
|
295
|
+
return that;
|
296
|
+
};
|
297
|
+
|
298
|
+
Exhibit.Type = function(t) {
|
299
|
+
var that = { };
|
300
|
+
|
301
|
+
that.name = t;
|
302
|
+
that.custom = { };
|
303
|
+
|
304
|
+
return that;
|
305
|
+
};
|
306
|
+
|
307
|
+
Exhibit.Property = function(p) {
|
308
|
+
var that = { };
|
309
|
+
|
310
|
+
that.name = p;
|
311
|
+
|
312
|
+
that.getValueType = function() {
|
313
|
+
that.valueType;
|
314
|
+
};
|
315
|
+
|
316
|
+
return that;
|
317
|
+
}
|
318
|
+
|
319
|
+
Exhibit.DataSource = function(options) {
|
320
|
+
var that = { },
|
321
|
+
set = Exhibit.Set(),
|
322
|
+
labelProperty, typeProperty, uriProperty;
|
323
|
+
that.options = options;
|
324
|
+
|
325
|
+
if(typeof(sources[options.source]) != "undefined") {
|
326
|
+
return sources[options.source];
|
327
|
+
}
|
328
|
+
|
329
|
+
sources[options.source] = that;
|
330
|
+
|
331
|
+
that.source = options.source;
|
332
|
+
that.events = { };
|
333
|
+
that.events.onModelChange = fluid.event.getEventFirer();
|
334
|
+
that.events.onBeforeLoadingTypes = fluid.event.getEventFirer();
|
335
|
+
that.events.onBeforeLoadingProperties = fluid.event.getEventFirer();
|
336
|
+
that.events.onBeforeLoadingItems = fluid.event.getEventFirer();
|
337
|
+
that.events.onAfterLoadingTypes = fluid.event.getEventFirer();
|
338
|
+
that.events.onAfterLoadingProperties = fluid.event.getEventFirer();
|
339
|
+
that.events.onAfterLoadingItems = fluid.event.getEventFirer();
|
340
|
+
|
341
|
+
that.types = { };
|
342
|
+
that.properties = { };
|
343
|
+
|
344
|
+
that.spo = { };
|
345
|
+
that.ops = { };
|
346
|
+
that.items = set.items;
|
347
|
+
|
348
|
+
that.types["Item"] = Exhibit.Type("Item");
|
349
|
+
|
350
|
+
labelProperty = Exhibit.Property("label");
|
351
|
+
labelProperty.uri = "http://www.w3.org/2000/01/rdf-schema#label";
|
352
|
+
labelProperty.valueType = "text";
|
353
|
+
labelProperty.label = "Label";
|
354
|
+
labelProperty.pluralLabel = "Labels";
|
355
|
+
labelProperty.reverseLabel = "";
|
356
|
+
labelProperty.reversePluralLabel = "";
|
357
|
+
labelProperty.groupingLabel = "";
|
358
|
+
labelProperty.reverseGroupingLabel = "";
|
359
|
+
that.properties["label"] = labelProperty;
|
360
|
+
|
361
|
+
typeProperty = Exhibit.Property("type");
|
362
|
+
typeProperty.uri = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
|
363
|
+
typeProperty.valueType = "text";
|
364
|
+
typeProperty.label = "type";
|
365
|
+
typeProperty.pluralLabel = "types";
|
366
|
+
typeProperty.reverseLabel = "";
|
367
|
+
typeProperty.reversePluralLabel = "";
|
368
|
+
typeProperty.groupingLabel = "";
|
369
|
+
typeProperty.reverseGroupingLabel = "";
|
370
|
+
that.properties["type"] = typeProperty;
|
371
|
+
|
372
|
+
uriProperty = Exhibit.Property("uri");
|
373
|
+
uriProperty.uri = "http://dh.tamu.edu/ns/fabulator/exhibit/1.0#uri";
|
374
|
+
uriProperty.valueType = "uri";
|
375
|
+
uriProperty.label = "URI";
|
376
|
+
uriProperty.pluralLabel = "URIs";
|
377
|
+
uriProperty.reverseLabel = "URI of";
|
378
|
+
uriProperty.reversePluralLabel = "URIs of";
|
379
|
+
uriProperty.groupingLabel = "URIs";
|
380
|
+
uriProperty.reverseGroupingLabel = "things named by these URIs";
|
381
|
+
that.properties["uri"] = uriProperty;
|
382
|
+
|
383
|
+
that.getItem = function(id) {
|
384
|
+
if(id in that.spo) {
|
385
|
+
return that.spo[id];
|
386
|
+
}
|
387
|
+
return { };
|
388
|
+
};
|
389
|
+
|
390
|
+
that.fetchData = function() {
|
391
|
+
/* TODO: make the URI building configurable */
|
392
|
+
$.ajax({
|
393
|
+
url: "/api/exhibits/" + options.source + ".json",
|
394
|
+
dataType: 'json',
|
395
|
+
success: function(data, textStatus) {
|
396
|
+
that.loadData(data);
|
397
|
+
}
|
398
|
+
});
|
399
|
+
};
|
400
|
+
|
401
|
+
that.loadData = function(data, baseURI) {
|
402
|
+
if(typeof baseURI == "undefined") {
|
403
|
+
baseURI = location.href;
|
404
|
+
}
|
405
|
+
|
406
|
+
if("types" in data) {
|
407
|
+
that.loadTypes(data.types, baseURI);
|
408
|
+
}
|
409
|
+
|
410
|
+
if("properties" in data) {
|
411
|
+
that.loadProperties(data.properties, baseURI);
|
412
|
+
}
|
413
|
+
|
414
|
+
if("items" in data) {
|
415
|
+
that.loadItems(data.items, baseURI);
|
416
|
+
}
|
417
|
+
|
418
|
+
that.events.onModelChange.fire(that);
|
419
|
+
};
|
420
|
+
|
421
|
+
var canonicalBaseURI = function(baseURI) {
|
422
|
+
var lastChar = baseURI.substr(baseURI.length - 1);
|
423
|
+
if( lastChar == "#" ) {
|
424
|
+
baseURI = baseURI.substr(0, baseURI.length-1) + "/";
|
425
|
+
}
|
426
|
+
else if( lastChar != "/" && lastChar != ":" ) {
|
427
|
+
baseURI += "/";
|
428
|
+
}
|
429
|
+
return baseURI;
|
430
|
+
};
|
431
|
+
|
432
|
+
that.loadTypes = function(types, baseURI) {
|
433
|
+
var typeID, typeEntry, type, p;
|
434
|
+
|
435
|
+
that.events.onBeforeLoadingTypes.fire(that);
|
436
|
+
try {
|
437
|
+
baseURI = canonicalBaseURI(baseURI);
|
438
|
+
for(typeID in types) {
|
439
|
+
if( typeof(typeID) != "string") { continue; }
|
440
|
+
typeEntry = types[typeID];
|
441
|
+
if( typeof(typeEntry) != "object") { continue; }
|
442
|
+
|
443
|
+
if( typeID in that.types ) {
|
444
|
+
type = that.types[typeID];
|
445
|
+
}
|
446
|
+
else {
|
447
|
+
type = Exhibit.Type(typeID);
|
448
|
+
that.types[typeID] = type;
|
449
|
+
}
|
450
|
+
|
451
|
+
for(p in typeEntry) {
|
452
|
+
type.custom[p] = typeEntry[p];
|
453
|
+
}
|
454
|
+
|
455
|
+
if(!("uri" in type.custom)) {
|
456
|
+
type.custom.uri = baseURI + "type#" + encodeURIComponent(typeID);
|
457
|
+
}
|
458
|
+
if(!("label" in type.custom)) {
|
459
|
+
type.custom.label = typeID;
|
460
|
+
}
|
461
|
+
}
|
462
|
+
that.events.onAfterLoadingTypes.fire(that);
|
463
|
+
}
|
464
|
+
catch(e) {
|
465
|
+
console.log("loadTypes failed:", e);
|
466
|
+
}
|
467
|
+
};
|
468
|
+
|
469
|
+
that.loadProperties = function(properties, baseURI) {
|
470
|
+
var propertyID, propertyEntry, property;
|
471
|
+
|
472
|
+
that.events.onBeforeLoadingProperties.fire(that);
|
473
|
+
try {
|
474
|
+
baseURI = canonicalBaseURI(baseURI);
|
475
|
+
|
476
|
+
for(propertyID in properties) {
|
477
|
+
if( typeof(propertyID) != "string") { continue; }
|
478
|
+
propertyEntry = properties[propertyID];
|
479
|
+
if( typeof(propertyEntry) != "object" ) { continue; }
|
480
|
+
|
481
|
+
if(propertyID in that.properties) {
|
482
|
+
property = that.properties[propertyID];
|
483
|
+
}
|
484
|
+
else {
|
485
|
+
property = Exhibit.Property(propertyID, that);
|
486
|
+
that.properties[propertyID] = property;
|
487
|
+
}
|
488
|
+
|
489
|
+
property.uri = ("uri" in propertyEntry) ? propertyEntry.uri : (baseURI + "property#" + encodeURIComponent(propertyID));
|
490
|
+
property.valueType = ("valueType" in propertyEntry) ? propertyEntry.valueType : "text";
|
491
|
+
|
492
|
+
property.label = ("label" in propertyEntry) ? propertyEntry.label : propertyID;
|
493
|
+
property.pluralLabel = ("pluralLabel" in propertyEntry) ? propertyEntry.pluralLabel : property.label;
|
494
|
+
property.reverseLabel = ("reverseLabel" in propertyEntry) ? propertyEntry.reverseLabel : "!" + property.label;
|
495
|
+
property.reversePluralLabel = ("reversePluralLabel" in propertyEntry) ? propertyEntry.reversePluralLabel : "!" + property.pluralLabel;
|
496
|
+
property.groupingLabel = ("groupingLabel" in propertyEntry) ? propertyEntry.groupingLabel : property.label;
|
497
|
+
property.reverseGroupingLabel = ("reverseGroupingLabel" in propertyEntry) ? propertyEntry.reverseGroupingLabel : "!" + property.reverseLabel;
|
498
|
+
|
499
|
+
if( "origin" in propertyEntry) {
|
500
|
+
property.origin = propertyEntry.origin;
|
501
|
+
}
|
502
|
+
}
|
503
|
+
|
504
|
+
that.events.onAfterLoadingProperties.fire(that);
|
505
|
+
}
|
506
|
+
catch(e) {
|
507
|
+
console.log("loadProperties failed: ", e);
|
508
|
+
}
|
509
|
+
};
|
510
|
+
|
511
|
+
that.loadItems = function(items, baseURI) {
|
512
|
+
var spo, ops, indexTriple, i, entry, n;
|
513
|
+
|
514
|
+
var indexPut = function(index, x, y, z) {
|
515
|
+
var hash = index[x],
|
516
|
+
array, i, n;
|
517
|
+
|
518
|
+
if(!hash) {
|
519
|
+
hash = { };
|
520
|
+
index[x] = hash;
|
521
|
+
}
|
522
|
+
|
523
|
+
array = hash[y];
|
524
|
+
|
525
|
+
if(!array) {
|
526
|
+
array = new Array();
|
527
|
+
hash[y] = array;
|
528
|
+
}
|
529
|
+
else {
|
530
|
+
for(i = 0, n = array.length; i < n; i++) {
|
531
|
+
if(z == array[i]) { return ; }
|
532
|
+
}
|
533
|
+
}
|
534
|
+
array.push(z);
|
535
|
+
};
|
536
|
+
|
537
|
+
|
538
|
+
that.events.onBeforeLoadingItems.fire(that);
|
539
|
+
try {
|
540
|
+
baseURI = canonicalBaseURI(baseURI);
|
541
|
+
|
542
|
+
indexTriple = function(s,p,o) {
|
543
|
+
indexPut(that.spo, s, p, o);
|
544
|
+
indexPut(that.ops, o, p, s);
|
545
|
+
};
|
546
|
+
|
547
|
+
for(i = 0, n = items.length; i < n; i++) {
|
548
|
+
entry = items[i];
|
549
|
+
if( typeof(entry) == "object" ) {
|
550
|
+
that.loadItem(entry, indexTriple, baseURI);
|
551
|
+
}
|
552
|
+
}
|
553
|
+
that.events.onAfterLoadingItems.fire(that);
|
554
|
+
}
|
555
|
+
catch(e) {
|
556
|
+
console.log("loadItems failed: ", e);
|
557
|
+
}
|
558
|
+
};
|
559
|
+
|
560
|
+
that.loadItem = function(item, indexFn, baseURI) {
|
561
|
+
var id, label, uri, type, isArray, p, i, n;
|
562
|
+
|
563
|
+
if(!("label" in item) && !("id" in item)) {
|
564
|
+
console.log("Item entry has no label and no id: ", item);
|
565
|
+
return;
|
566
|
+
}
|
567
|
+
|
568
|
+
if(!("label" in item)) {
|
569
|
+
id = item.id;
|
570
|
+
if( !that.items.contains(id) ) {
|
571
|
+
console.log("Cannot add new item containing no label: ", item);
|
572
|
+
}
|
573
|
+
}
|
574
|
+
else {
|
575
|
+
label = item.label;
|
576
|
+
id = ("id" in item) ? item.id : label;
|
577
|
+
uri = ("uri" in item) ? item.uri : (baseURI + "item#" + encodeURIComponent(id));
|
578
|
+
type = ("type" in item) ? item.type : "Item";
|
579
|
+
|
580
|
+
isArray = function(obj) {
|
581
|
+
if(obj.constructor.toString().indexOf("Array") == -1)
|
582
|
+
return false;
|
583
|
+
else
|
584
|
+
return true;
|
585
|
+
};
|
586
|
+
|
587
|
+
if(isArray(label)) label = label[0];
|
588
|
+
if(isArray(id)) id = id[0];
|
589
|
+
if(isArray(uri)) uri = uri[0];
|
590
|
+
if(isArray(type)) type = type[0];
|
591
|
+
|
592
|
+
set.add(id);
|
593
|
+
|
594
|
+
indexFn(id, "uri", uri);
|
595
|
+
indexFn(id, "label", label);
|
596
|
+
indexFn(id, "type", type);
|
597
|
+
indexFn(id, "id", id);
|
598
|
+
|
599
|
+
that.ensureTypeExists(type, baseURI);
|
600
|
+
}
|
601
|
+
|
602
|
+
for(p in item) {
|
603
|
+
if( typeof(p) != "string" ) { continue; }
|
604
|
+
|
605
|
+
if(p != "uri" && p != "label" && p != "id" && p != "type") {
|
606
|
+
that.ensurePropertyExists(p, baseURI);
|
607
|
+
|
608
|
+
v = item[p];
|
609
|
+
if(v instanceof Array) {
|
610
|
+
for(i = 0, n = v.length; i < n; i++) {
|
611
|
+
indexFn(id, p, v[i]);
|
612
|
+
}
|
613
|
+
}
|
614
|
+
else if( v != undefined && v != null ) {
|
615
|
+
indexFn(id, p, v);
|
616
|
+
}
|
617
|
+
}
|
618
|
+
}
|
619
|
+
};
|
620
|
+
|
621
|
+
that.ensureTypeExists = function(typeID, baseURI) {
|
622
|
+
var type;
|
623
|
+
|
624
|
+
if(!(typeID in that.types)) {
|
625
|
+
type = Exhibit.Type(typeID);
|
626
|
+
type.custom.uri = baseURI + "type#" + encodeURIComponent(typeID);
|
627
|
+
type.custom.label = typeID;
|
628
|
+
that.types[typeID] = type;
|
629
|
+
}
|
630
|
+
};
|
631
|
+
|
632
|
+
that.ensurePropertyExists = function(propertyID, baseURI) {
|
633
|
+
var property;
|
634
|
+
|
635
|
+
if(!(propertyID in that.properties)) {
|
636
|
+
property = Exhibit.Property(propertyID);
|
637
|
+
property.uri = baseURI + "property#" + encodeURIComponent(propertyID);
|
638
|
+
property.valueType = "text";
|
639
|
+
|
640
|
+
property.label = propertyID;
|
641
|
+
property.pluralLabel = property.label;
|
642
|
+
|
643
|
+
property.reverseLabel = "reverse of " + property.label;
|
644
|
+
property.reversePluralLabel = "reverse of " + property.pluralLabel;
|
645
|
+
|
646
|
+
property.groupingLabel = property.label;
|
647
|
+
property.reverseGroupingLabel = property.reverseLabel;
|
648
|
+
|
649
|
+
that.properties[propertyID] = property;
|
650
|
+
}
|
651
|
+
};
|
652
|
+
|
653
|
+
that.getProperty = function(property) {
|
654
|
+
return property in that.properties ? that.properties[property] : null;
|
655
|
+
};
|
656
|
+
|
657
|
+
var indexFillSet = function(index, x, y, set, filter) {
|
658
|
+
var hash = index[x],
|
659
|
+
array, i, n, z;
|
660
|
+
|
661
|
+
if(hash) {
|
662
|
+
array = hash[y];
|
663
|
+
if(array) {
|
664
|
+
if(filter) {
|
665
|
+
for(i = 0, n = array.length; i < n; i += 1) {
|
666
|
+
z = array[i];
|
667
|
+
if( filter.contains(z) ) {
|
668
|
+
set.add(z);
|
669
|
+
}
|
670
|
+
}
|
671
|
+
}
|
672
|
+
else {
|
673
|
+
for(i = 0, n = array.length; i < n; i += 1) {
|
674
|
+
set.add(array[i]);
|
675
|
+
}
|
676
|
+
}
|
677
|
+
}
|
678
|
+
}
|
679
|
+
};
|
680
|
+
|
681
|
+
var getUnion = function(index, xSet, y, set, filter) {
|
682
|
+
if(!set) {
|
683
|
+
set = Exhibit.Set();
|
684
|
+
}
|
685
|
+
|
686
|
+
xSet.visit(function(x) {
|
687
|
+
indexFillSet(index, x, y, set, filter);
|
688
|
+
});
|
689
|
+
return set;
|
690
|
+
};
|
691
|
+
|
692
|
+
that.getObjectsUnion = function(subjects, p, set, filter) {
|
693
|
+
return getUnion(that.spo, subjects, p, set, filter);
|
694
|
+
};
|
695
|
+
|
696
|
+
that.getSubjectsUnion = function(objects, p, set, filter) {
|
697
|
+
return getUnion(that.ops, objects, p, set, filter);
|
698
|
+
};
|
699
|
+
|
700
|
+
/*
|
701
|
+
var indexCount = function(index, x, y, filter) {
|
702
|
+
var hash = index[x],
|
703
|
+
count = 0, i, n, z;
|
704
|
+
|
705
|
+
if(hash) {
|
706
|
+
array = hash[y];
|
707
|
+
if(array) {
|
708
|
+
if(filter) {
|
709
|
+
for(i = 0, n = array.length; i < n; i += 1) {
|
710
|
+
z = array[i];
|
711
|
+
if( filter.contains(z) ) {
|
712
|
+
count += 1;
|
713
|
+
}
|
714
|
+
}
|
715
|
+
}
|
716
|
+
else {
|
717
|
+
count += array.length;
|
718
|
+
}
|
719
|
+
}
|
720
|
+
}
|
721
|
+
|
722
|
+
return count;
|
723
|
+
};
|
724
|
+
|
725
|
+
var getCount = function(index, xSet, y, filter) {
|
726
|
+
var count = 0;
|
727
|
+
|
728
|
+
xSet.visit(function(x) {
|
729
|
+
count += indexCount(index, x, y, filter);
|
730
|
+
});
|
731
|
+
return count;
|
732
|
+
};
|
733
|
+
|
734
|
+
that.countSubjects = function(objects, p, filter) {
|
735
|
+
return getCount(that.ops, objects, p, filter);
|
736
|
+
};
|
737
|
+
|
738
|
+
that.countObjects = function(objects, p, filter) {
|
739
|
+
return getCount(that.spo, objects, p, filter);
|
740
|
+
};
|
741
|
+
*/
|
742
|
+
|
743
|
+
return that;
|
744
|
+
};
|
745
|
+
})(jQuery, Fabulator.Exhibit);
|