wontomedia 0.1.1 → 0.2.0
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/Rakefile +9 -5
- data/VERSION.yml +2 -2
- data/app/controllers/admin_controller.rb +34 -11
- data/app/controllers/connections_controller.rb +8 -2
- data/app/controllers/items_controller.rb +213 -68
- data/app/helpers/format_helper.rb +22 -1
- data/app/helpers/items_helper.rb +43 -0
- data/app/models/connection.rb +128 -100
- data/app/models/item.rb +96 -0
- data/app/views/connections/_spo_select_controls.html.erb +65 -31
- data/app/views/connections/edit.html.erb +7 -2
- data/app/views/connections/index.html.erb +11 -4
- data/app/views/connections/show.html.erb +13 -5
- data/app/views/items/_class_select.html.erb +41 -0
- data/app/views/items/_content_examples.html.erb +21 -18
- data/app/views/items/_core_tasks.html.erb +40 -5
- data/app/views/items/_form_fields.html.erb +4 -4
- data/app/views/items/_inline_item_add_form.html.erb +48 -0
- data/app/views/items/_inline_scalar_add_form.html.erb +36 -0
- data/app/views/items/_most_populous_classes.html.erb +42 -0
- data/app/views/items/_type_select.html.erb +28 -26
- data/app/views/items/edit.html.erb +8 -2
- data/app/views/items/index.html.erb +5 -1
- data/app/views/items/new.html.erb +69 -54
- data/app/views/items/newpop.html.erb +18 -3
- data/app/views/items/show.html.erb +110 -7
- data/app/views/layouts/application.html.erb +2 -2
- data/app/views/layouts/base.html.erb +4 -2
- data/app/views/layouts/home.html.erb +2 -2
- data/assets/wontomedia-sample.rb +2 -0
- data/config/asset_packages.yml +1 -0
- data/config/cucumber.yml +11 -13
- data/db/fixtures/connections.yml +85 -4
- data/db/fixtures/items.yml +140 -8
- data/db/migrate/20100315135952_provide_scalar_objects.rb +32 -0
- data/db/migrate/20100321042343_add_timestamp_columns.rb +33 -0
- data/db/schema.rb +17 -11
- data/default-custom/app/views/items/home.html.erb +1 -1
- data/default-custom/public/stylesheets/wm.css +21 -4
- data/lib/helpers/connection_helper.rb +84 -1
- data/lib/helpers/item_helper.rb +16 -3
- data/lib/tasks/cucumber.rake +0 -2
- data/public/images/transparent_ltblue_background.png +0 -0
- data/public/images/{alert_background.png → transparent_white_background.png} +0 -0
- data/public/javascripts/forConnectionsForms.js +182 -41
- data/public/javascripts/forItemsForms.js +40 -5
- data/public/javascripts/forItemsShow.js +27 -0
- data/public/javascripts/itemCreatePopup.js +10 -3
- metadata +13 -5
@@ -0,0 +1,32 @@
|
|
1
|
+
# WontoMedia - a wontology web application
|
2
|
+
# Copyright (C) 2010 - Glen E. Ivey
|
3
|
+
# www.wontology.com
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License version
|
7
|
+
# 3 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program in the file COPYING and/or LICENSE. If not,
|
16
|
+
# see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
|
19
|
+
class ProvideScalarObjects < ActiveRecord::Migration
|
20
|
+
def self.up
|
21
|
+
add_column :connections, :kind_of_obj, :string # really an enum
|
22
|
+
add_column :connections, :scalar_obj, :string
|
23
|
+
|
24
|
+
# all existing Connections have Items as their objects
|
25
|
+
execute 'UPDATE connections SET kind_of_obj="item"'
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.down
|
29
|
+
remove_column :connections, :kind_of_object
|
30
|
+
remove_column :connections, :scalar_obj
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# WontoMedia - a wontology web application
|
2
|
+
# Copyright (C) 2010 - Glen E. Ivey
|
3
|
+
# www.wontology.com
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License version
|
7
|
+
# 3 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program in the file COPYING and/or LICENSE. If not,
|
16
|
+
# see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
|
19
|
+
class AddTimestampColumns < ActiveRecord::Migration
|
20
|
+
def self.up
|
21
|
+
add_column :items, :created_at, :datetime
|
22
|
+
add_column :items, :updated_at, :datetime
|
23
|
+
add_column :connections, :created_at, :datetime
|
24
|
+
add_column :connections, :updated_at, :datetime
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.down
|
28
|
+
remove_column :items, :created_at
|
29
|
+
remove_column :items, :updated_at
|
30
|
+
remove_column :connections, :created_at
|
31
|
+
remove_column :connections, :updated_at
|
32
|
+
end
|
33
|
+
end
|
data/db/schema.rb
CHANGED
@@ -9,22 +9,28 @@
|
|
9
9
|
#
|
10
10
|
# It's strongly recommended to check this file into your version control system.
|
11
11
|
|
12
|
-
ActiveRecord::Schema.define(:version =>
|
12
|
+
ActiveRecord::Schema.define(:version => 20100321042343) do
|
13
13
|
|
14
14
|
create_table "connections", :force => true do |t|
|
15
|
-
t.integer
|
16
|
-
t.integer
|
17
|
-
t.integer
|
18
|
-
t.integer
|
19
|
-
t.integer
|
15
|
+
t.integer "subject_id"
|
16
|
+
t.integer "predicate_id"
|
17
|
+
t.integer "obj_id"
|
18
|
+
t.integer "connection_desc_id"
|
19
|
+
t.integer "flags", :default => 0, :null => false
|
20
|
+
t.string "kind_of_obj"
|
21
|
+
t.string "scalar_obj"
|
22
|
+
t.datetime "created_at"
|
23
|
+
t.datetime "updated_at"
|
20
24
|
end
|
21
25
|
|
22
26
|
create_table "items", :force => true do |t|
|
23
|
-
t.string
|
24
|
-
t.string
|
25
|
-
t.text
|
26
|
-
t.string
|
27
|
-
t.integer
|
27
|
+
t.string "name"
|
28
|
+
t.string "title"
|
29
|
+
t.text "description"
|
30
|
+
t.string "sti_type"
|
31
|
+
t.integer "flags", :default => 0, :null => false
|
32
|
+
t.datetime "created_at"
|
33
|
+
t.datetime "updated_at"
|
28
34
|
end
|
29
35
|
|
30
36
|
end
|
@@ -42,7 +42,7 @@
|
|
42
42
|
<%= render :partial => "content_examples" %>
|
43
43
|
<% end -%>
|
44
44
|
<% content_for :content_lower_narrow do %>
|
45
|
-
<%= render :partial => "
|
45
|
+
<%= render :partial => "most_populous_classes" %>
|
46
46
|
<% end -%>
|
47
47
|
<% content_for :content_bottom do %>
|
48
48
|
<div class="horizontal-link-list">
|
@@ -63,6 +63,14 @@ div#fancybox-outer {
|
|
63
63
|
|
64
64
|
|
65
65
|
/* settings for the basic division of pages into areas and boxes */
|
66
|
+
.page-title-text {
|
67
|
+
position: absolute;
|
68
|
+
top: 0;
|
69
|
+
left: 15.5%;
|
70
|
+
height: 8ex;
|
71
|
+
width: 69.7%;
|
72
|
+
overflow: hidden;
|
73
|
+
}
|
66
74
|
.content {
|
67
75
|
padding: 2px;
|
68
76
|
background-color: white;
|
@@ -89,12 +97,21 @@ div#fancybox-outer {
|
|
89
97
|
.headline:first-child {
|
90
98
|
margin-top: 0;
|
91
99
|
}
|
92
|
-
|
100
|
+
|
101
|
+
h2.subheading {
|
93
102
|
font-size: 150%;
|
103
|
+
}
|
104
|
+
h3.subheading {
|
105
|
+
font-size: 120%;
|
106
|
+
text-decoration: underline;
|
107
|
+
}
|
108
|
+
.subheading {
|
94
109
|
font-weight: bold;
|
95
110
|
color: #b0b0ff;
|
111
|
+
margin-top: 0;
|
96
112
|
margin-bottom: 1.3ex;
|
97
113
|
}
|
114
|
+
|
98
115
|
.fine-print {
|
99
116
|
font-size: 60%;
|
100
117
|
color: #040460;
|
@@ -212,10 +229,10 @@ p + table { margin-bottom: 1.5em; }
|
|
212
229
|
|
213
230
|
#block-help {
|
214
231
|
float: right;
|
215
|
-
border-width:
|
232
|
+
border-width: 2px;
|
216
233
|
border-color: #e8e8ff;
|
217
234
|
border-style: none solid solid;
|
218
|
-
background:
|
235
|
+
background: url("/images/transparent_ltblue_background.png") repeat;
|
219
236
|
padding: 0 0.3em;
|
220
237
|
height: 2.7ex;
|
221
238
|
font-size: 200%;
|
@@ -229,7 +246,7 @@ p + table { margin-bottom: 1.5em; }
|
|
229
246
|
z-index: 150;
|
230
247
|
font-size: 110%;
|
231
248
|
font-weight: bold;
|
232
|
-
background: url("/images/
|
249
|
+
background: url("/images/transparent_white_background.png") repeat;
|
233
250
|
text-align: center;
|
234
251
|
}
|
235
252
|
#alert_box_close_link {
|
@@ -34,8 +34,91 @@ module ConnectionHelper
|
|
34
34
|
result = ""
|
35
35
|
connections.each do |connection|
|
36
36
|
result << "<##{connection.subject.name}> <##{connection.predicate.name}> "
|
37
|
-
|
37
|
+
if connection.kind_of_obj == Connection::OBJECT_KIND_ITEM
|
38
|
+
result << "<##{connection.obj.name}> .\n"
|
39
|
+
else
|
40
|
+
result << "\"#{connection.scalar_obj}\" .\n"
|
41
|
+
end
|
38
42
|
end
|
39
43
|
result
|
40
44
|
end
|
45
|
+
|
46
|
+
# An operator usable for sorting, returns 0 for a==b, <0 for a<b
|
47
|
+
def self.compare(a, b, factor_hash = {})
|
48
|
+
# sort relationships using built-in predicates to the bottom
|
49
|
+
aflag = a.predicate.flags & Item::DATA_IS_UNALTERABLE
|
50
|
+
bflag = b.predicate.flags & Item::DATA_IS_UNALTERABLE
|
51
|
+
return aflag - bflag if aflag != bflag
|
52
|
+
|
53
|
+
# sort relationships to scalar values above those with item objects
|
54
|
+
# connection with filled-in scalar valued object
|
55
|
+
if a.kind_of_obj && b.kind_of_obj && a.kind_of_obj != b.kind_of_obj
|
56
|
+
return a.kind_of_obj == Connection::OBJECT_KIND_ITEM ? 1 : -1
|
57
|
+
end
|
58
|
+
if a.kind_of_obj.nil? || b.kind_of_obj.nil?
|
59
|
+
# connection with blank object intended to be a scalar
|
60
|
+
a_kind = Connection.first( :conditions => [
|
61
|
+
"subject_id = ? AND predicate_id = ?", a.predicate_id,
|
62
|
+
Item.find_by_name('has_scalar_object') ])
|
63
|
+
b_kind = Connection.first( :conditions => [
|
64
|
+
"subject_id = ? AND predicate_id = ?", b.predicate_id,
|
65
|
+
Item.find_by_name('has_scalar_object') ])
|
66
|
+
if a_kind != b_kind
|
67
|
+
return a_kind.nil? ? 1 : -1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# relationships w/ predicates constrained by max_uses_per_item:
|
72
|
+
# sort lower maximums closer to top of list. Sort unconstrained
|
73
|
+
# predicates as "infinite maximum"
|
74
|
+
max_uses = Item.find_by_name('max_uses_per_item')
|
75
|
+
a_max = Connection.first( :conditions => [
|
76
|
+
"subject_id = ? AND predicate_id = ?", a.predicate_id, max_uses.id ])
|
77
|
+
unless a_max.nil?
|
78
|
+
a_max = a_max.scalar_obj.nil? ? nil : a_max.scalar_obj.to_i
|
79
|
+
end
|
80
|
+
b_max = Connection.first( :conditions => [
|
81
|
+
"subject_id = ? AND predicate_id = ?", b.predicate_id, max_uses.id ])
|
82
|
+
unless b_max.nil?
|
83
|
+
b_max = b_max.scalar_obj.nil? ? nil : b_max.scalar_obj.to_i
|
84
|
+
end
|
85
|
+
unless a_max == b_max
|
86
|
+
return -1 if b_max.nil?
|
87
|
+
return 1 if a_max.nil?
|
88
|
+
return a_max - b_max
|
89
|
+
end
|
90
|
+
|
91
|
+
a_id = a.predicate_id
|
92
|
+
b_id = b.predicate_id
|
93
|
+
|
94
|
+
# sort by "predicate external factor" hash, higher numbers better
|
95
|
+
# (this is intended to support, among other things, sorting based
|
96
|
+
# on the number of times the same predicate is used in the list of
|
97
|
+
# connections being sorted. Requires caller to make a counting
|
98
|
+
# pass over the sort set first to build the hash
|
99
|
+
a_count = factor_hash[a_id].nil? ? 0 : factor_hash[a_id]
|
100
|
+
b_count = factor_hash[b_id].nil? ? 0 : factor_hash[b_id]
|
101
|
+
return b_count - a_count if a_count != b_count
|
102
|
+
|
103
|
+
# sort by property ID order (this is essentially arbitrary, but
|
104
|
+
# ensures the sort order is stable and that subsequent factors
|
105
|
+
# only affect sorting within groups of connections all referencing
|
106
|
+
# the same property item)
|
107
|
+
return a_id - b_id if a_id != b_id
|
108
|
+
|
109
|
+
# sort connections with missing objects (e.g. "add here"
|
110
|
+
# place-holders) below others
|
111
|
+
a_blank = a.kind_of_obj.nil? ||
|
112
|
+
(a.kind_of_obj == Connection::OBJECT_KIND_ITEM ?
|
113
|
+
a.obj : a.scalar_obj ) == nil
|
114
|
+
b_blank = b.kind_of_obj.nil? ||
|
115
|
+
(b.kind_of_obj == Connection::OBJECT_KIND_ITEM ?
|
116
|
+
b.obj : b.scalar_obj ) == nil
|
117
|
+
return a_blank ? 1 : -1 if a_blank != b_blank
|
118
|
+
|
119
|
+
# sort connections whose objects are built-in below others
|
120
|
+
aflag = a.obj.nil? ? 0 : a.obj.flags & Item::DATA_IS_UNALTERABLE
|
121
|
+
bflag = b.obj.nil? ? 0 : b.obj.flags & Item::DATA_IS_UNALTERABLE
|
122
|
+
return aflag - bflag
|
123
|
+
end
|
41
124
|
end
|
data/lib/helpers/item_helper.rb
CHANGED
@@ -119,10 +119,23 @@ module ItemHelper
|
|
119
119
|
|
120
120
|
# Takes an Item object, +n+, and returns a symbol-indexed hash
|
121
121
|
# containing each of the Item's data fields.
|
122
|
-
def self.item_to_hash(
|
122
|
+
def self.item_to_hash(item)
|
123
123
|
# Really ought to be doing this programatically from the schema....
|
124
|
-
{ :id =>
|
125
|
-
:
|
124
|
+
{ :id => item.id, :name => item.name, :title => item.title,
|
125
|
+
:flags => item.flags, :description => item.description,
|
126
|
+
:sti_type => item.sti_type, :class_item_id => item.class_item_id }
|
127
|
+
end
|
128
|
+
|
129
|
+
# Map from an Item.name of a built-in item representing an item type
|
130
|
+
# (e.g., is_instance_of ItemType_Item) to the matching internal
|
131
|
+
# Item.sti_type string
|
132
|
+
def self.sti_type_for_ItemType( type_item_name )
|
133
|
+
case type_item_name
|
134
|
+
when 'Value_ItemType_Category' then 'CategoryItem'
|
135
|
+
when 'Value_ItemType_Individual' then 'IndividualItem'
|
136
|
+
when 'Value_ItemType_Property' then 'PropertyItem'
|
137
|
+
else ''
|
138
|
+
end
|
126
139
|
end
|
127
140
|
|
128
141
|
|
data/lib/tasks/cucumber.rake
CHANGED
@@ -36,14 +36,12 @@ begin
|
|
36
36
|
Cucumber::Rake::Task.new({:static_ok => 'db:test:prepare'},
|
37
37
|
'Run non-Selenium features that should pass') do |t|
|
38
38
|
t.binary = vendored_cucumber_binary
|
39
|
-
t.fork = false
|
40
39
|
t.profile = "static_acceptance"
|
41
40
|
end
|
42
41
|
|
43
42
|
Cucumber::Rake::Task.new({:dynamic_ok => 'db:test:prepare'},
|
44
43
|
'Run need-Selenium-to-test features that should pass') do |t|
|
45
44
|
t.binary = vendored_cucumber_binary
|
46
|
-
t.fork = false
|
47
45
|
t.profile = "dynamic_acceptance"
|
48
46
|
end
|
49
47
|
|
Binary file
|
File without changes
|
@@ -16,22 +16,38 @@
|
|
16
16
|
// see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
|
19
|
-
var selectElems
|
20
|
-
var connectionSubmit;
|
21
|
-
var l = window.location;
|
22
|
-
var base = l.protocol + "//" + l.hostname + ":" + l.port;
|
23
|
-
var lastValue = {}
|
24
|
-
|
19
|
+
var selectElems = [ "subject", "predicate", "obj" ];
|
25
20
|
|
26
21
|
// define fields subject to check, order they occur in form
|
27
|
-
|
28
|
-
var
|
29
|
-
|
22
|
+
// these arrays must have same index order:
|
23
|
+
var requiredConnectionElements =
|
24
|
+
[ "subject", "predicate", "kind_of_obj", "obj", "submit" ];
|
25
|
+
var connectionElementNames =
|
26
|
+
[ "Subject selector", "Relationship selector",
|
27
|
+
"Object kind", "Object content" ];
|
28
|
+
var controlIds =
|
29
|
+
[ [ "connection_subject_id" ],
|
30
|
+
[ "connection_predicate_id" ],
|
31
|
+
[ "connection_kind_of_obj_scalar", "connection_kind_of_obj_item" ],
|
32
|
+
[ "connection_scalar_obj", "connection_obj_id" ],
|
33
|
+
[ "connection_submit" ] // this one doesn't really matter--won't be used
|
34
|
+
];
|
35
|
+
var controlTypes =
|
36
|
+
[ [ "value" ],
|
37
|
+
[ "value" ],
|
38
|
+
[ "checked", "checked" ],
|
39
|
+
[ "value", "value" ],
|
40
|
+
[ "checked" ] // this one doesn't really matter--won't be used
|
41
|
+
];
|
30
42
|
|
31
43
|
// encoding: -1 -> haven't checked yet
|
32
44
|
// false -> no error
|
33
45
|
// true -> error condition present
|
34
|
-
var connectionFormErrors = {};
|
46
|
+
var connectionFormErrors = {}; // don't display errors until user goes past
|
47
|
+
|
48
|
+
var lastValue = {} // don't error check unless changed
|
49
|
+
var connectionSubmit; // $(submit-botton) for convenience
|
50
|
+
|
35
51
|
|
36
52
|
|
37
53
|
if ((typeof inAConnectionsForm !== 'undefined') && inAConnectionsForm){
|
@@ -40,7 +56,8 @@ if ((typeof inAConnectionsForm !== 'undefined') && inAConnectionsForm){
|
|
40
56
|
lastValue = {
|
41
57
|
subject : $('connection_subject_id').value,
|
42
58
|
predicate : $('connection_predicate_id').value,
|
43
|
-
obj : $('connection_obj_id').value
|
59
|
+
obj : $('connection_obj_id').value,
|
60
|
+
scalar : $('connection_scalar_obj').value
|
44
61
|
};
|
45
62
|
|
46
63
|
for (var c=0; c < requiredConnectionElements.length-1; c++)
|
@@ -48,24 +65,31 @@ if ((typeof inAConnectionsForm !== 'undefined') && inAConnectionsForm){
|
|
48
65
|
creatingNewConnection ? -1 : false;
|
49
66
|
|
50
67
|
for (var c=0; c < selectElems.length; c++){
|
51
|
-
|
52
|
-
|
68
|
+
createIdOnchangeHandler(selectElems[c]);
|
69
|
+
createIdOnfocusHandler(selectElems[c]);
|
53
70
|
}
|
71
|
+
createKindHandlers();
|
72
|
+
createScalarHandlers();
|
54
73
|
|
55
74
|
if (creatingNewConnection)
|
56
75
|
// connections/new -- can't submit a blank form
|
57
76
|
makeButtonSeemDisabled(connectionSubmit);
|
58
77
|
else // connections/##/edit -- can submit as-is form
|
59
78
|
makeButtonSeemEnabled(connectionSubmit);
|
60
|
-
|
61
79
|
connectionSubmit.observe('click', submitOnclickHandler);
|
80
|
+
connectionSubmit.observe('focus',
|
81
|
+
function(){ onfocusBehavior(connectionSubmit); } );
|
82
|
+
|
83
|
+
// do after browser has done final layout of all the select controls
|
84
|
+
setDescDivsWidths([ 'subject', 'predicate', 'obj' ]);
|
85
|
+
syncEnabledStateOfObjectControls();
|
62
86
|
}
|
63
87
|
|
64
88
|
|
65
|
-
function
|
89
|
+
function createIdOnchangeHandler(thisName){
|
66
90
|
var thisElem = $('connection_' + thisName + '_id');
|
67
|
-
if (thisElem == null)
|
68
|
-
|
91
|
+
if (thisElem == null) // only deal with ID select controls
|
92
|
+
return;
|
69
93
|
thisElem.observe('change',
|
70
94
|
function(){ // nest all these fn defs for closure
|
71
95
|
if (thisElem.value != lastValue[thisName]){
|
@@ -78,23 +102,12 @@ function createOnchangeHandler(thisName){
|
|
78
102
|
}
|
79
103
|
else if (thisElem.value == "-1"){
|
80
104
|
divToBlank(thisName);
|
81
|
-
var
|
82
|
-
itemCreatePopup(thisElem,
|
105
|
+
var popupType = (thisName == "predicate") ? "verb" : "noun";
|
106
|
+
itemCreatePopup(thisElem, lastLast, popupType, null);
|
83
107
|
}
|
84
108
|
else {
|
85
109
|
clearError(thisName);
|
86
|
-
|
87
|
-
new Ajax.Request(base + "/w/items/" + thisElem.value + ".json", {
|
88
|
-
method: 'get',
|
89
|
-
onSuccess: function(response){
|
90
|
-
var itemObject = response.responseJSON;
|
91
|
-
var key = getFirstHashKey(itemObject);
|
92
|
-
divToText(thisName, itemObject[key]["description"]);
|
93
|
-
},
|
94
|
-
onFailure: function(){
|
95
|
-
divToBlank(thisName);
|
96
|
-
}
|
97
|
-
});
|
110
|
+
loadItemDescDiv(thisName, thisElem);
|
98
111
|
}
|
99
112
|
refreshSubmitState();
|
100
113
|
}
|
@@ -102,6 +115,44 @@ function createOnchangeHandler(thisName){
|
|
102
115
|
);
|
103
116
|
}
|
104
117
|
|
118
|
+
function loadItemDescDiv(thisName, thisElem){
|
119
|
+
divToWorking(thisName);
|
120
|
+
|
121
|
+
var winloc = window.location;
|
122
|
+
var base = winloc.protocol + "//" + winloc.hostname + ":" + winloc.port;
|
123
|
+
new Ajax.Request(base + "/w/items/" + thisElem.value + ".json", {
|
124
|
+
method: 'get',
|
125
|
+
onSuccess: function(response){
|
126
|
+
var itemObject = response.responseJSON;
|
127
|
+
var key = getFirstHashKey(itemObject);
|
128
|
+
divToText(thisName, itemObject[key]["description"]);
|
129
|
+
},
|
130
|
+
onFailure: function(){
|
131
|
+
divToBlank(thisName);
|
132
|
+
}
|
133
|
+
});
|
134
|
+
}
|
135
|
+
|
136
|
+
function createScalarHandlers(){
|
137
|
+
var name = 'scalar';
|
138
|
+
var scalar = $("connection_scalar_obj");
|
139
|
+
|
140
|
+
scalar.observe('change',
|
141
|
+
function(){ // nest all these fn defs for closure
|
142
|
+
if (scalar.value != lastValue[name]){
|
143
|
+
var lastLast = lastValue[name];
|
144
|
+
lastValue[name] = scalar.value;
|
145
|
+
|
146
|
+
if (scalar.value == "") // pretend we're same as 'obj_id' select
|
147
|
+
flagConnectionAsRequired('obj');
|
148
|
+
else
|
149
|
+
clearError('obj');
|
150
|
+
refreshSubmitState();
|
151
|
+
}
|
152
|
+
}
|
153
|
+
);
|
154
|
+
}
|
155
|
+
|
105
156
|
function getFirstHashKey(hashObj){
|
106
157
|
for (var key in hashObj)
|
107
158
|
return key;
|
@@ -130,19 +181,57 @@ function divToText(divName, divText){
|
|
130
181
|
}
|
131
182
|
|
132
183
|
|
133
|
-
function
|
184
|
+
function createIdOnfocusHandler(thisName){
|
134
185
|
var thisElem = $('connection_' + thisName + '_id');
|
135
186
|
if (thisElem == null)
|
136
|
-
|
187
|
+
return;
|
188
|
+
thisElem.observe('focus', function(){ onfocusBehavior(thisElem); } );
|
189
|
+
}
|
190
|
+
|
191
|
+
function createKindHandlers(){
|
192
|
+
thisElem = $('connection_kind_of_obj_scalar');
|
193
|
+
thisElem.observe('focus', function(){ onfocusBehavior(thisElem); } );
|
194
|
+
thisElem.observe('change', kindOnchangeBehavior);
|
195
|
+
|
196
|
+
thisElem = $('connection_kind_of_obj_item');
|
137
197
|
thisElem.observe('focus', function(){ onfocusBehavior(thisElem); } );
|
198
|
+
thisElem.observe('change', kindOnchangeBehavior);
|
199
|
+
}
|
200
|
+
|
201
|
+
function kindOnchangeBehavior(){
|
202
|
+
syncEnabledStateOfObjectControls();
|
203
|
+
|
204
|
+
var itemChecked = $('connection_kind_of_obj_item' ).checked;
|
205
|
+
var scalarChecked = $('connection_kind_of_obj_scalar').checked;
|
206
|
+
|
207
|
+
var hasAValue = itemChecked || scalarChecked;
|
208
|
+
if (hasAValue)
|
209
|
+
clearError('kind_of_obj');
|
210
|
+
else
|
211
|
+
flagConnectionAsRequired('kind_of_obj');
|
212
|
+
|
213
|
+
if (connectionFormErrors['obj'] != -1){
|
214
|
+
var value = null;
|
215
|
+
if (itemChecked)
|
216
|
+
value = $('connection_obj_id').value;
|
217
|
+
else
|
218
|
+
value = $('connection_scalar_obj').value;
|
219
|
+
if (value != null && value != "")
|
220
|
+
clearError('obj'); // if selected control has a value, great
|
221
|
+
else
|
222
|
+
flagConnectionAsRequired('obj'); // otherwise, error (ignore other ctrl)
|
223
|
+
}
|
224
|
+
|
225
|
+
refreshSubmitState();
|
138
226
|
}
|
139
227
|
|
140
228
|
function onfocusBehavior(elem){
|
141
|
-
|
229
|
+
// find this control's position in flag arrays. Value of rCE[c] is
|
230
|
+
// always a substring of matching control's id=''
|
142
231
|
var c;
|
143
232
|
for (c=0; c < requiredConnectionElements.length; c++){
|
144
233
|
var re = new RegExp(requiredConnectionElements[c]);
|
145
|
-
var mtch =
|
234
|
+
var mtch = elem.id.match(re);
|
146
235
|
if (mtch != null && mtch.length > 0)
|
147
236
|
break;
|
148
237
|
}
|
@@ -152,27 +241,56 @@ function onfocusBehavior(elem){
|
|
152
241
|
|
153
242
|
var lastToCheck = c-1;
|
154
243
|
for (c=0; c <= lastToCheck; c++){
|
155
|
-
var
|
156
|
-
|
157
|
-
|
158
|
-
|
244
|
+
var hasAValue = false;
|
245
|
+
var equivalentIds = controlIds[c];
|
246
|
+
|
247
|
+
perControlLoop:
|
248
|
+
for (var cn=0; cn < equivalentIds.length; cn++){
|
249
|
+
|
250
|
+
control = $(equivalentIds[cn]);
|
251
|
+
if (control.disabled)
|
252
|
+
continue perControlLoop;
|
253
|
+
|
254
|
+
if (controlTypes[c][cn] == "checked"){
|
255
|
+
if (control.checked == true){
|
256
|
+
hasAValue = true;
|
257
|
+
break;
|
258
|
+
}
|
259
|
+
}
|
260
|
+
else { // Type == "value"
|
261
|
+
if (control.value != null && control.value != ""){
|
262
|
+
hasAValue = true;
|
263
|
+
break;
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
|
268
|
+
if (hasAValue)
|
159
269
|
clearError(requiredConnectionElements[c]);
|
270
|
+
else
|
271
|
+
flagConnectionAsRequired(requiredConnectionElements[c]);
|
160
272
|
}
|
161
273
|
refreshSubmitState();
|
162
274
|
}
|
163
275
|
|
164
276
|
function flagConnectionAsRequired(elemName){
|
165
277
|
connectionFormErrors[elemName] = true;
|
166
|
-
|
278
|
+
maybeSetTextClass(elemName, "helpTextFlagged");
|
167
279
|
$(elemName + "_error_icon").src = "/images/error_error_icon.png";
|
168
280
|
}
|
169
281
|
|
170
282
|
function clearError(elemName){
|
171
283
|
connectionFormErrors[elemName] = false;
|
172
|
-
|
284
|
+
maybeSetTextClass(elemName, "");
|
173
285
|
$(elemName + "_error_icon").src = "/images/blank_error_icon.png";
|
174
286
|
}
|
175
287
|
|
288
|
+
function maybeSetTextClass(elemName, newClass){
|
289
|
+
var requiredText = $(elemName + "_required");
|
290
|
+
if (requiredText)
|
291
|
+
requiredText.className = newClass
|
292
|
+
}
|
293
|
+
|
176
294
|
function refreshSubmitState(){
|
177
295
|
var detectedAtLeastOneError = false;
|
178
296
|
for (var c =0; c < requiredConnectionElements.length-1; c++)
|
@@ -216,3 +334,26 @@ function maybeShowErrorDialog(){
|
|
216
334
|
}
|
217
335
|
return accum;
|
218
336
|
}
|
337
|
+
|
338
|
+
function syncEnabledStateOfObjectControls(){
|
339
|
+
var scalarDisabled = !($('connection_kind_of_obj_scalar').checked);
|
340
|
+
$('connection_scalar_obj').disabled = scalarDisabled;
|
341
|
+
if (!scalarDisabled){
|
342
|
+
divToBlank('obj');
|
343
|
+
lastValue['obj'] = "";
|
344
|
+
}
|
345
|
+
|
346
|
+
var idDisabled = !($('connection_kind_of_obj_item')).checked;
|
347
|
+
control = $('connection_obj_id');
|
348
|
+
control.disabled = idDisabled;
|
349
|
+
if (!idDisabled && (control.value != lastValue['obj']) )
|
350
|
+
loadItemDescDiv('obj', control);
|
351
|
+
}
|
352
|
+
|
353
|
+
function setDescDivsWidths(names){
|
354
|
+
for (var c=0; c < names.length; c++){
|
355
|
+
var descDiv = $(names[c] + "_desc");
|
356
|
+
var w = $("connection_" + names[c] + "_id").getWidth();
|
357
|
+
descDiv.style.width = w + "px";
|
358
|
+
}
|
359
|
+
}
|