383 """return field's *typed* value""" |
386 """return field's *typed* value""" |
384 value = field.initial |
387 value = field.initial |
385 if callable(value): |
388 if callable(value): |
386 value = value(self) |
389 value = value(self) |
387 return value |
390 return value |
388 |
|
389 def _errex_match_field(self, errex, field): |
|
390 """return true if the field has some error in given validation exception |
|
391 """ |
|
392 return field.name in errex.errors |
|
393 |
391 |
394 def form_field_error(self, field): |
392 def form_field_error(self, field): |
395 """return validation error for widget's field, if any""" |
393 """return validation error for widget's field, if any""" |
396 errex = self.req.data.get('formerrors') |
394 errex = self.req.data.get('formerrors') |
397 if errex and self._errex_match_field(errex, field): |
395 if errex and self._errex_match_field(errex, field): |
398 self.req.data['displayederrors'].add(field.name) |
396 self.req.data['displayederrors'].add(field.name) |
399 return u'<span class="error">%s</span>' % errex.errors[field.name] |
397 return u'<span class="error">%s</span>' % errex.errors[field.name] |
400 return u'' |
398 return u'' |
401 |
399 |
402 def form_field_format(self, field): |
400 def form_field_format(self, field): |
|
401 """return MIME type used for the given (text or bytes) field""" |
403 return self.req.property_value('ui.default-text-format') |
402 return self.req.property_value('ui.default-text-format') |
404 |
403 |
405 def form_field_encoding(self, field): |
404 def form_field_encoding(self, field): |
|
405 """return encoding used for the given (text) field""" |
406 return self.req.encoding |
406 return self.req.encoding |
407 |
407 |
408 def form_field_name(self, field): |
408 def form_field_name(self, field): |
|
409 """return qualified name for the given field""" |
409 return field.name |
410 return field.name |
410 |
411 |
411 def form_field_id(self, field): |
412 def form_field_id(self, field): |
|
413 """return dom id for the given field""" |
412 return field.id |
414 return field.id |
413 |
415 |
414 def form_field_vocabulary(self, field, limit=None): |
416 def form_field_vocabulary(self, field, limit=None): |
|
417 """return vocabulary for the given field. Should be overriden in |
|
418 specific forms using fields which requires some vocabulary |
|
419 """ |
415 raise NotImplementedError |
420 raise NotImplementedError |
|
421 |
|
422 def _errex_match_field(self, errex, field): |
|
423 """return true if the field has some error in given validation exception |
|
424 """ |
|
425 return field.name in errex.errors |
416 |
426 |
417 |
427 |
418 class EntityFieldsForm(FieldsForm): |
428 class EntityFieldsForm(FieldsForm): |
419 __select__ = (match_kwargs('entity') | (one_line_rset & non_final_entity())) |
429 __select__ = (match_kwargs('entity') | (one_line_rset & non_final_entity())) |
420 |
430 |
433 # If we need to directly attach the new object to another one |
443 # If we need to directly attach the new object to another one |
434 for linkto in self.req.list_form_param('__linkto'): |
444 for linkto in self.req.list_form_param('__linkto'): |
435 self.form_add_hidden('__linkto', linkto) |
445 self.form_add_hidden('__linkto', linkto) |
436 msg = '%s %s' % (msg, self.req._('and linked')) |
446 msg = '%s %s' % (msg, self.req._('and linked')) |
437 self.form_add_hidden('__message', msg) |
447 self.form_add_hidden('__message', msg) |
|
448 |
|
449 def _errex_match_field(self, errex, field): |
|
450 """return true if the field has some error in given validation exception |
|
451 """ |
|
452 return errex.eid == self.edited_entity.eid and field.name in errex.errors |
|
453 |
|
454 def _relation_vocabulary(self, rtype, targettype, role, |
|
455 limit=None, done=None): |
|
456 """return unrelated entities for a given relation and target entity type |
|
457 for use in vocabulary |
|
458 """ |
|
459 if done is None: |
|
460 done = set() |
|
461 rset = self.edited_entity.unrelated(rtype, targettype, role, limit) |
|
462 res = [] |
|
463 for entity in rset.entities(): |
|
464 if entity.eid in done: |
|
465 continue |
|
466 done.add(entity.eid) |
|
467 res.append((entity.view('combobox'), entity.eid)) |
|
468 return res |
|
469 |
|
470 def _form_field_default_value(self, field, load_bytes): |
|
471 defaultattr = 'default_%s' % field.name |
|
472 if hasattr(self.edited_entity, defaultattr): |
|
473 # XXX bw compat, default_<field name> on the entity |
|
474 warn('found %s on %s, should be set on a specific form' |
|
475 % (defaultattr, self.edited_entity.id), DeprecationWarning) |
|
476 value = getattr(self.edited_entity, defaultattr) |
|
477 if callable(value): |
|
478 value = value() |
|
479 else: |
|
480 value = super(EntityFieldsForm, self).form_field_value(field, |
|
481 load_bytes) |
|
482 return value |
438 |
483 |
439 def form_build_context(self, values=None): |
484 def form_build_context(self, values=None): |
440 self.form_add_entity_hiddens(self.edited_entity.e_schema) |
485 """overriden to add edit[s|o] hidden fields and to ensure schema fields |
441 return super(EntityFieldsForm, self).form_build_context(values) |
486 have eidparam set to True |
442 |
487 |
443 def form_add_entity_hiddens(self, eschema): |
488 edit[s|o] hidden fields are used t o indicate the value for the |
|
489 associated field before the (potential) modification made when |
|
490 submitting the form. |
|
491 """ |
|
492 eschema = self.edited_entity.e_schema |
444 for field in self.fields[:]: |
493 for field in self.fields[:]: |
445 for field in field.actual_fields(self): |
494 for field in field.actual_fields(self): |
446 fieldname = field.name |
495 fieldname = field.name |
447 if fieldname != 'eid' and ( |
496 if fieldname != 'eid' and ( |
448 (eschema.has_subject_relation(fieldname) or |
497 (eschema.has_subject_relation(fieldname) or |
449 eschema.has_object_relation(fieldname))): |
498 eschema.has_object_relation(fieldname))): |
450 field.eidparam = True |
499 field.eidparam = True |
451 self.fields.append(self.form_entity_hidden_field(field)) |
500 self.fields.append(HiddenInitialValueField(field)) |
452 |
501 return super(EntityFieldsForm, self).form_build_context(values) |
453 def form_entity_hidden_field(self, field): |
|
454 """returns the hidden field which will indicate the value |
|
455 before the modification |
|
456 """ |
|
457 # Only RelationField has a `role` attribute, others are used |
|
458 # to describe attribute fields => role is 'subject' |
|
459 if getattr(field, 'role', 'subject') == 'subject': |
|
460 name = 'edits-%s' % field.name |
|
461 else: |
|
462 name = 'edito-%s' % field.name |
|
463 return HiddenInitialValueField(field, name=name) |
|
464 |
502 |
465 def form_field_value(self, field, load_bytes=False): |
503 def form_field_value(self, field, load_bytes=False): |
466 """return field's *typed* value |
504 """return field's *typed* value |
467 |
505 |
468 overriden to deal with |
506 overriden to deal with |
507 if entity.has_eid(): |
545 if entity.has_eid(): |
508 value = [ent.eid for ent in getattr(entity, attr)] |
546 value = [ent.eid for ent in getattr(entity, attr)] |
509 else: |
547 else: |
510 value = self._form_field_default_value(field, load_bytes) |
548 value = self._form_field_default_value(field, load_bytes) |
511 return value |
549 return value |
512 |
|
513 def _form_field_default_value(self, field, load_bytes): |
|
514 defaultattr = 'default_%s' % field.name |
|
515 if hasattr(self.edited_entity, defaultattr): |
|
516 # XXX bw compat, default_<field name> on the entity |
|
517 warn('found %s on %s, should be set on a specific form' |
|
518 % (defaultattr, self.edited_entity.id), DeprecationWarning) |
|
519 value = getattr(self.edited_entity, defaultattr) |
|
520 if callable(value): |
|
521 value = value() |
|
522 else: |
|
523 value = super(EntityFieldsForm, self).form_field_value(field, |
|
524 load_bytes) |
|
525 return value |
|
526 |
550 |
527 def form_field_format(self, field): |
551 def form_field_format(self, field): |
|
552 """return MIME type used for the given (text or bytes) field""" |
528 entity = self.edited_entity |
553 entity = self.edited_entity |
529 if field.eidparam and entity.e_schema.has_metadata(field.name, 'format') and ( |
554 if field.eidparam and entity.e_schema.has_metadata(field.name, 'format') and ( |
530 entity.has_eid() or '%s_format' % field.name in entity): |
555 entity.has_eid() or '%s_format' % field.name in entity): |
531 return self.edited_entity.attr_metadata(field.name, 'format') |
556 return self.edited_entity.attr_metadata(field.name, 'format') |
532 return self.req.property_value('ui.default-text-format') |
557 return self.req.property_value('ui.default-text-format') |
533 |
558 |
534 def form_field_encoding(self, field): |
559 def form_field_encoding(self, field): |
|
560 """return encoding used for the given (text) field""" |
535 entity = self.edited_entity |
561 entity = self.edited_entity |
536 if field.eidparam and entity.e_schema.has_metadata(field.name, 'encoding') and ( |
562 if field.eidparam and entity.e_schema.has_metadata(field.name, 'encoding') and ( |
537 entity.has_eid() or '%s_encoding' % field.name in entity): |
563 entity.has_eid() or '%s_encoding' % field.name in entity): |
538 return self.edited_entity.attr_metadata(field.name, 'encoding') |
564 return self.edited_entity.attr_metadata(field.name, 'encoding') |
539 return super(EntityFieldsForm, self).form_field_encoding(field) |
565 return super(EntityFieldsForm, self).form_field_encoding(field) |
540 |
|
541 |
|
542 def _errex_match_field(self, errex, field): |
|
543 """return true if the field has some error in given validation exception |
|
544 """ |
|
545 return errex.eid == self.edited_entity.eid and field.name in errex.errors |
|
546 |
566 |
547 def form_field_name(self, field): |
567 def form_field_name(self, field): |
|
568 """return qualified name for the given field""" |
548 if field.eidparam: |
569 if field.eidparam: |
549 return eid_param(field.name, self.edited_entity.eid) |
570 return eid_param(field.name, self.edited_entity.eid) |
550 return field.name |
571 return field.name |
551 |
572 |
552 def form_field_id(self, field): |
573 def form_field_id(self, field): |
|
574 """return dom id for the given field""" |
553 if field.eidparam: |
575 if field.eidparam: |
554 return eid_param(field.id, self.edited_entity.eid) |
576 return eid_param(field.id, self.edited_entity.eid) |
555 return field.id |
577 return field.id |
556 |
578 |
557 def form_field_vocabulary(self, field, limit=None): |
579 def form_field_vocabulary(self, field, limit=None): |
|
580 """return vocabulary for the given field""" |
558 role, rtype = field.role, field.name |
581 role, rtype = field.role, field.name |
559 method = '%s_%s_vocabulary' % (role, rtype) |
582 method = '%s_%s_vocabulary' % (role, rtype) |
560 try: |
583 try: |
561 vocabfunc = getattr(self, method) |
584 vocabfunc = getattr(self, method) |
562 except AttributeError: |
585 except AttributeError: |
610 result = [] |
633 result = [] |
611 rsetsize = None |
634 rsetsize = None |
612 for subjtype in rtype.subjects(entity.e_schema): |
635 for subjtype in rtype.subjects(entity.e_schema): |
613 if limit is not None: |
636 if limit is not None: |
614 rsetsize = limit - len(result) |
637 rsetsize = limit - len(result) |
615 result += self.relation_vocabulary(rtype, subjtype, 'object', |
638 result += self._relation_vocabulary(rtype, subjtype, 'object', |
616 rsetsize, done) |
639 rsetsize, done) |
617 if limit is not None and len(result) >= limit: |
640 if limit is not None and len(result) >= limit: |
618 break |
641 break |
619 return result |
642 return result |
620 |
643 |
621 def relation_vocabulary(self, rtype, targettype, role, |
|
622 limit=None, done=None): |
|
623 if done is None: |
|
624 done = set() |
|
625 rset = self.edited_entity.unrelated(rtype, targettype, role, limit) |
|
626 res = [] |
|
627 for entity in rset.entities(): |
|
628 if entity.eid in done: |
|
629 continue |
|
630 done.add(entity.eid) |
|
631 res.append((entity.view('combobox'), entity.eid)) |
|
632 return res |
|
633 |
|
634 def subject_in_state_vocabulary(self, rschema, limit=None): |
644 def subject_in_state_vocabulary(self, rschema, limit=None): |
635 """vocabulary method for the in_state relation, looking for |
645 """vocabulary method for the in_state relation, looking for relation's |
636 relation's object entities (i.e. self is the subject) according |
646 object entities (i.e. self is the subject) according to initial_state, |
637 to initial_state, state_of and next_state relation |
647 state_of and next_state relation |
638 """ |
648 """ |
639 entity = self.edited_entity |
649 entity = self.edited_entity |
640 if not entity.has_eid() or not entity.in_state: |
650 if not entity.has_eid() or not entity.in_state: |
641 # get the initial state |
651 # get the initial state |
642 rql = 'Any S where S state_of ET, ET name %(etype)s, ET initial_state S' |
652 rql = 'Any S where S state_of ET, ET name %(etype)s, ET initial_state S' |