Skip to content

Commit

Permalink
Updated yodel_query.js to support the new validations format
Browse files Browse the repository at this point in the history
  • Loading branch information
willcannings committed Apr 15, 2012
1 parent bb1ccef commit 89e0936
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 48 deletions.
2 changes: 1 addition & 1 deletion lib/yodel/models/core/validations/required_validation.rb
@@ -1,5 +1,5 @@
class RequiredValidation < Validation
validate do
invalidate_with("is_required") if value.blank? && !value.is_a?(FalseClass)
invalidate_with("is required") if value.blank? && !value.is_a?(FalseClass)
end
end
25 changes: 15 additions & 10 deletions lib/yodel/models/pages/form_builder.rb
Expand Up @@ -43,8 +43,8 @@ def form_for_section(section)

def field_row(name, field=nil)
field = @record.fields[name.to_s] if field.nil?
html = "<div class='contains-field-type-#{field.options['type']}'>"
html << label(name).to_s << "<div>"
html = "<div class='yodel-row yodel-contains-field-type-#{field.options['type']}'>"
html << label(name).to_s << "<div class='yodel-row-content'>"

if field.default_input_type == :embedded
html << field(name, blank_record: true).to_s
Expand Down Expand Up @@ -181,11 +181,11 @@ def field(name, options={}, &block)

element.tap do |element|
class_name = invalid ? 'invalid' : (@record.new? ? 'new' : 'valid')
class_name += " field-type-#{field.options['type']}"
element.set_attribute(:id, input_name.gsub(/\W/, '_'))
element.set_attribute(:name, input_name)
element.set_attribute(:class, class_name)
element.set_attribute(:placeholder, field.placeholder || '')
class_name += " yodel-field yodel-field-type-#{field.options['type']}"
element.set_attribute('id', input_name.gsub(/\W/, '_'))
element.set_attribute('name', input_name)
element.set_attribute('class', class_name)
element.set_attribute('placeholder', field.placeholder || '')
element.set_attribute('data-field', input_name)
options.each do |name, value|
element.set_attribute(name.to_s, value)
Expand Down Expand Up @@ -276,7 +276,7 @@ def render
# render a default form
if @block.nil?
if @embedded_record
form_for_section(@record.field_sections[nil])
wrap_with_yodel_record_element(form_for_section(@record.field_sections[nil]))
else
form_element(@record.field_sections[nil])
end
Expand All @@ -285,22 +285,27 @@ def render
else
if @embedded_record
buffer = Ember::Template.buffer_from_block(@block)
buffer << Ember::Template.content_from_block(@block, self)
buffer << wrap_with_yodel_record_element(Ember::Template.content_from_block(@block, self).join)
else
Ember::Template.wrap_content_block(@block, self) {|content| form_element(content.join)}
end
end

end


private
def wrap_with_yodel_record_element(content)
"<span class='yodel-record' data-record-id='#{@record.id}'>#{content}</span>"
end

def form_element(content)
params = {
'action' => @action,
'method' => 'post',
'enctype' => 'multipart/form-data',
'data-remote' => (!!@remote).to_s,
'class' => 'yodel-record',
'data-record-id' => @record.id.to_s,
'id' => @id
}.merge(@params)

Expand Down
131 changes: 94 additions & 37 deletions lib/yodel/public/core/js/yodel_jquery.js
@@ -1,5 +1,14 @@
var Yodel = {};

// Debug
Yodel.Debug = {
show_errors: true,
log: function() {
if(Yodel.Debug.show_errors)
console.log.call(arguments);
}
}

// Security
Yodel.Security = {
login: function(credentials, path) {
Expand Down Expand Up @@ -84,50 +93,101 @@ jQuery('.yodel-remote-action').live('click', function(event, element) {

// Forms
Yodel.Forms = {
clearStatusStates: function(form) {
jQuery(form).find('span[data-handles]').each(function(index, statusData) {
var status = jQuery(statusData).children().first();
if(status) {
status.html('');
status.removeClass('new');
status.removeClass('valid');
status.removeClass('invalid');
clearErrors: function(form) {
jQuery(form).find('.yodel-field, .yodel-field-status').each(function(index, el) {
var element = jQuery(el);

if(element.hasClass('.yodel-field-status')) {
element = element.children().first();
element.html('');
} else {
element.data('errors', []);
}

element.removeClass('new');
element.removeClass('valid');
element.removeClass('invalid');
});
},

setState: function(fieldName, form, state, message) {
// FIXME: assumes all fields have a status element as well
// check the form contains a field element for this message
var field = jQuery(form).find('*[data-field=' + fieldName + ']').first();
if(!field[0]) {
console.log("Form does not contain a field for: " + fieldName);
return;
setErrors: function(form, errors) {
// validations are represented as:
// {record_id: {field: [errors]},
// embedded_record_id: {field: [errors]} ...}

for(var record_id in errors) {
var record_errors = errors[record_id];
var selector_prefix = '.yodel-record[data-record-id=' + record_id + '] ';

for(var field_name in record_errors) {
var field_selector = selector_prefix + ' .yodel-field[data-field=' + field_name + ']';
var field_element = jQuery(field_selector).first();

if(field_element.length) {
var field_errors = field_element.data('errors') || [];
field_errors = field_errors.concat(record_errors[field_name]);
field_element.data('errors', field_errors);
field_element.addClass('invalid');
}
}
}

var statusData = jQuery(form).find('span[data-handles*=' + fieldName + ']').first();
var status = statusData.children().first();
},

drawStatusStates: function(form) {
jQuery(form).find('.yodel-field').each(function(index, el) {
// find the field's record
var field = jQuery(el);
var field_type = field.attr('data-field');
var errors = field.data('errors') || [];
var record = field.closest('.yodel-record');
if(!record.length) {
Yodel.Debug.log('Could not find parent record for', field);
return;
}

// only continue if the field has an associated status element
var status = record.find('.yodel-field-status[data-handles*=' + field_type + ']').first();
if(!status.length)
return;

if(errors.length == 0) {
var message = null;
var state = 'valid';
} else {
// combine the errors together into a sentence - errors are
// returned as a list and without the field type leading.
var message = field_type.toLowerCase().replace(/_/g, ' ').replace(/\w/, function(chr) {return chr.toUpperCase()});
message += " " + errors.join(', ');
var state = 'invalid';
}

Yodel.Forms.setStatusState(form, field, status, state, message);
});
},

setStatusState: function(form, field, status, state, message) {
var status_child = status.children().first();

// submission of a form never transitions a field to the new state
status.removeClass('new');
status_child.removeClass('new');

if(state == 'valid') {
if(!status.hasClass('invalid')) {
status.removeClass('invalid');
status.addClass('valid');
if(!status_child.hasClass('invalid')) {
status_child.removeClass('invalid');
status_child.addClass('valid');
}
field.removeClass('invalid');
field.addClass('valid');
} else {
status.addClass('invalid');
status.removeClass('valid');
status_child.addClass('invalid');
status_child.removeClass('valid');
field.addClass('invalid');
field.removeClass('valid');
}

// either use the supplied message, or override it with
// a static message provided in the layout
var staticMessage = statusData.attr('data-' + state + '-text');
var staticMessage = status.attr('data-' + state + '-text');
if(staticMessage)
message = staticMessage;
else
Expand All @@ -138,11 +198,13 @@ Yodel.Forms = {

// insert or replace the status element's text. Statuses may
// correspond to more than one field, hence concatenating msgs.
if(message)
if(status.html() == '')
status.html(message);
if(message) {
var current_status_text = status_child.html();
if(current_status_text == '')
status_child.html(message);
else
status.html(status.html() + ', ' + message);
status_child.html(current_status_text + ', ' + message);
}
},

handleFailure: function(activityElement, form, data) {
Expand Down Expand Up @@ -210,14 +272,9 @@ Yodel.Forms = {
if(errorsFunction) {
errorsFunction(errors);
} else {
Yodel.Forms.clearStatusStates(form);
form.find('*[data-field]').each(function(index, element) {
var fieldName = jQuery(element).attr('data-field');
if(json.errors[fieldName])
Yodel.Forms.setState(fieldName, form, 'invalid', json.errors[fieldName]);
else
Yodel.Forms.setState(fieldName, form, 'valid');
});
Yodel.Forms.clearErrors(form);
Yodel.Forms.setErrors(form, errors);
Yodel.Forms.drawStatusStates(form);
}
}
});
Expand Down

0 comments on commit 89e0936

Please sign in to comment.