Summary: Port the remaining parts of the IPR form to Bootstrap, and fix
some bugs in the port - Legacy-Id: 8900
This commit is contained in:
parent
543ac4ecb7
commit
1124d6d018
|
@ -4,12 +4,16 @@ from django.utils.html import escape
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.urlresolvers import reverse as urlreverse
|
from django.core.urlresolvers import reverse as urlreverse
|
||||||
|
|
||||||
import debug # pyflakes:ignore
|
|
||||||
|
|
||||||
from ietf.doc.models import Document, DocAlias
|
from ietf.doc.models import Document, DocAlias
|
||||||
|
from ietf.doc.utils import uppercase_std_abbreviated_name
|
||||||
|
|
||||||
def select2_id_doc_name_json(objs):
|
def select2_id_doc_name_json(objs):
|
||||||
return json.dumps([{ "id": o.pk, "text": escape(o.name) } for o in objs])
|
return json.dumps([{ "id": o.pk, "text": escape(uppercase_std_abbreviated_name(o.name)) } for o in objs])
|
||||||
|
|
||||||
|
# FIXME: select2 version 4 uses a standard select for the AJAX case -
|
||||||
|
# switching to that would allow us to derive from the standard
|
||||||
|
# multi-select machinery in Django instead of the manual CharField
|
||||||
|
# stuff below
|
||||||
|
|
||||||
class SearchableDocumentsField(forms.CharField):
|
class SearchableDocumentsField(forms.CharField):
|
||||||
"""Server-based multi-select field for choosing documents using
|
"""Server-based multi-select field for choosing documents using
|
||||||
|
@ -32,7 +36,7 @@ class SearchableDocumentsField(forms.CharField):
|
||||||
|
|
||||||
super(SearchableDocumentsField, self).__init__(*args, **kwargs)
|
super(SearchableDocumentsField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.widget.attrs["class"] = "select2-field"
|
self.widget.attrs["class"] = "select2-field form-control"
|
||||||
self.widget.attrs["data-placeholder"] = hint_text
|
self.widget.attrs["data-placeholder"] = hint_text
|
||||||
if self.max_entries != None:
|
if self.max_entries != None:
|
||||||
self.widget.attrs["data-max-entries"] = self.max_entries
|
self.widget.attrs["data-max-entries"] = self.max_entries
|
||||||
|
@ -43,6 +47,8 @@ class SearchableDocumentsField(forms.CharField):
|
||||||
def prepare_value(self, value):
|
def prepare_value(self, value):
|
||||||
if not value:
|
if not value:
|
||||||
value = ""
|
value = ""
|
||||||
|
if isinstance(value, (int, long)):
|
||||||
|
value = str(value)
|
||||||
if isinstance(value, basestring):
|
if isinstance(value, basestring):
|
||||||
pks = self.parse_select2_value(value)
|
pks = self.parse_select2_value(value)
|
||||||
value = self.model.objects.filter(pk__in=pks)
|
value = self.model.objects.filter(pk__in=pks)
|
||||||
|
@ -82,7 +88,26 @@ class SearchableDocumentsField(forms.CharField):
|
||||||
|
|
||||||
return objs
|
return objs
|
||||||
|
|
||||||
|
class SearchableDocumentField(SearchableDocumentsField):
|
||||||
|
"""Specialized to only return one Document."""
|
||||||
|
def __init__(self, model=Document, *args, **kwargs):
|
||||||
|
kwargs["max_entries"] = 1
|
||||||
|
super(SearchableDocumentField, self).__init__(model=model, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
return super(SearchableDocumentField, self).clean(value).first()
|
||||||
|
|
||||||
class SearchableDocAliasesField(SearchableDocumentsField):
|
class SearchableDocAliasesField(SearchableDocumentsField):
|
||||||
def __init__(self, model=DocAlias, *args, **kwargs):
|
def __init__(self, model=DocAlias, *args, **kwargs):
|
||||||
super(SearchableDocAliasesField, self).__init__(model=model, *args, **kwargs)
|
super(SearchableDocAliasesField, self).__init__(model=model, *args, **kwargs)
|
||||||
|
|
||||||
|
class SearchableDocAliasField(SearchableDocumentsField):
|
||||||
|
"""Specialized to only return one DocAlias."""
|
||||||
|
def __init__(self, model=DocAlias, *args, **kwargs):
|
||||||
|
kwargs["max_entries"] = 1
|
||||||
|
super(SearchableDocAliasField, self).__init__(model=model, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
return super(SearchableDocAliasField, self).clean(value).first()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,73 +4,58 @@ from django.utils.html import escape
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.urlresolvers import reverse as urlreverse
|
from django.core.urlresolvers import reverse as urlreverse
|
||||||
|
|
||||||
import debug # pyflakes:ignore
|
|
||||||
|
|
||||||
from ietf.doc.models import DocAlias
|
|
||||||
from ietf.ipr.models import IprDisclosureBase
|
from ietf.ipr.models import IprDisclosureBase
|
||||||
|
|
||||||
def tokeninput_id_name_json(objs):
|
def select2_id_ipr_title_json(value):
|
||||||
"""Returns objects as JSON string.
|
return json.dumps([{ "id": o.pk, "text": escape(u"%s <%s>" % (o.title, o.time.date().isoformat())) } for o in value])
|
||||||
NOTE: double quotes in the object name are replaced with single quotes to avoid
|
|
||||||
problems with representation of the JSON string in the HTML widget attribute"""
|
|
||||||
def format_ipr(x):
|
|
||||||
text = x.title.replace('"',"'")
|
|
||||||
return escape(u"%s <%s>" % (text, x.time.date().isoformat()))
|
|
||||||
def format_doc(x):
|
|
||||||
return escape(x.name)
|
|
||||||
|
|
||||||
formatter = format_ipr if objs and isinstance(objs[0], IprDisclosureBase) else format_doc
|
class SearchableIprDisclosuresField(forms.CharField):
|
||||||
|
"""Server-based multi-select field for choosing documents using
|
||||||
return json.dumps([{ "id": o.pk, "name": formatter(o) } for o in objs])
|
select2.js.
|
||||||
|
|
||||||
class AutocompletedIprDisclosuresField(forms.CharField):
|
|
||||||
"""Tokenizing autocompleted multi-select field for choosing
|
|
||||||
IPR disclosures using jquery.tokeninput.js.
|
|
||||||
|
|
||||||
The field uses a comma-separated list of primary keys in a
|
The field uses a comma-separated list of primary keys in a
|
||||||
CharField element as its API, the tokeninput Javascript adds some
|
CharField element as its API with some extra attributes used by
|
||||||
selection magic on top of this so we have to pass it a JSON
|
the Javascript part."""
|
||||||
representation of ids and user-understandable labels."""
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
max_entries=None, # max number of selected objs
|
max_entries=None, # max number of selected objs
|
||||||
model=IprDisclosureBase,
|
model=IprDisclosureBase,
|
||||||
hint_text="Type in term(s) to search disclosure title",
|
hint_text="Type in terms to search disclosure title",
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
kwargs["max_length"] = 1000
|
kwargs["max_length"] = 1000
|
||||||
self.max_entries = max_entries
|
self.max_entries = max_entries
|
||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
super(AutocompletedIprDisclosuresField, self).__init__(*args, **kwargs)
|
super(SearchableIprDisclosuresField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.widget.attrs["class"] = "tokenized-field"
|
self.widget.attrs["class"] = "select2-field form-control"
|
||||||
self.widget.attrs["data-hint-text"] = hint_text
|
self.widget.attrs["data-placeholder"] = hint_text
|
||||||
if self.max_entries != None:
|
if self.max_entries != None:
|
||||||
self.widget.attrs["data-max-entries"] = self.max_entries
|
self.widget.attrs["data-max-entries"] = self.max_entries
|
||||||
|
|
||||||
def parse_tokenized_value(self, value):
|
def parse_select2_value(self, value):
|
||||||
return [x.strip() for x in value.split(",") if x.strip()]
|
return [x.strip() for x in value.split(",") if x.strip()]
|
||||||
|
|
||||||
def prepare_value(self, value):
|
def prepare_value(self, value):
|
||||||
if not value:
|
if not value:
|
||||||
value = ""
|
value = ""
|
||||||
if isinstance(value, basestring):
|
if isinstance(value, basestring):
|
||||||
pks = self.parse_tokenized_value(value)
|
pks = self.parse_select2_value(value)
|
||||||
value = self.model.objects.filter(pk__in=pks)
|
value = self.model.objects.filter(pk__in=pks)
|
||||||
if isinstance(value, self.model):
|
if isinstance(value, self.model):
|
||||||
value = [value]
|
value = [value]
|
||||||
|
|
||||||
self.widget.attrs["data-pre"] = tokeninput_id_name_json(value)
|
self.widget.attrs["data-pre"] = select2_id_ipr_title_json(value)
|
||||||
|
|
||||||
# doing this in the constructor is difficult because the URL
|
# doing this in the constructor is difficult because the URL
|
||||||
# patterns may not have been fully constructed there yet
|
# patterns may not have been fully constructed there yet
|
||||||
self.widget.attrs["data-ajax-url"] = urlreverse("ipr_ajax_search")
|
self.widget.attrs["data-ajax-url"] = urlreverse("ipr_ajax_search")
|
||||||
|
|
||||||
return ",".join(str(e.pk) for e in value)
|
return u",".join(unicode(e.pk) for e in value)
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
value = super(AutocompletedIprDisclosuresField, self).clean(value)
|
value = super(SearchableIprDisclosuresField, self).clean(value)
|
||||||
pks = self.parse_tokenized_value(value)
|
pks = self.parse_select2_value(value)
|
||||||
|
|
||||||
objs = self.model.objects.filter(pk__in=pks)
|
objs = self.model.objects.filter(pk__in=pks)
|
||||||
|
|
||||||
|
@ -83,75 +68,3 @@ class AutocompletedIprDisclosuresField(forms.CharField):
|
||||||
raise forms.ValidationError(u"You can select at most %s entries only." % self.max_entries)
|
raise forms.ValidationError(u"You can select at most %s entries only." % self.max_entries)
|
||||||
|
|
||||||
return objs
|
return objs
|
||||||
|
|
||||||
class AutocompletedDraftsField(AutocompletedIprDisclosuresField):
|
|
||||||
"""Version of AutocompletedPersonsField with the defaults right for Drafts."""
|
|
||||||
|
|
||||||
def __init__(self, model=DocAlias, hint_text="Type in name to search draft name",
|
|
||||||
*args, **kwargs):
|
|
||||||
super(AutocompletedDraftsField, self).__init__(model=model, hint_text=hint_text, *args, **kwargs)
|
|
||||||
|
|
||||||
def prepare_value(self, value):
|
|
||||||
if not value:
|
|
||||||
value = ""
|
|
||||||
if isinstance(value, basestring):
|
|
||||||
pks = self.parse_tokenized_value(value)
|
|
||||||
value = self.model.objects.filter(pk__in=pks)
|
|
||||||
if isinstance(value, self.model):
|
|
||||||
value = [value]
|
|
||||||
if isinstance(value, long):
|
|
||||||
value = self.model.objects.filter(pk=value)
|
|
||||||
|
|
||||||
self.widget.attrs["data-pre"] = tokeninput_id_name_json(value)
|
|
||||||
|
|
||||||
# doing this in the constructor is difficult because the URL
|
|
||||||
# patterns may not have been fully constructed there yet
|
|
||||||
self.widget.attrs["data-ajax-url"] = urlreverse("ipr_ajax_draft_search")
|
|
||||||
|
|
||||||
return ",".join(str(e.pk) for e in value)
|
|
||||||
|
|
||||||
class AutocompletedDraftField(AutocompletedDraftsField):
|
|
||||||
"""Version of AutocompletedEmailsField specialized to a single object."""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs["max_entries"] = 1
|
|
||||||
super(AutocompletedDraftField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self, value):
|
|
||||||
return super(AutocompletedDraftField, self).clean(value).first()
|
|
||||||
|
|
||||||
class AutocompletedRfcsField(AutocompletedIprDisclosuresField):
|
|
||||||
"""Version of AutocompletedPersonsField with the defaults right for Drafts."""
|
|
||||||
|
|
||||||
def __init__(self, model=DocAlias, hint_text="Type in the RFC number",
|
|
||||||
*args, **kwargs):
|
|
||||||
super(AutocompletedRfcsField, self).__init__(model=model, hint_text=hint_text, *args, **kwargs)
|
|
||||||
|
|
||||||
def prepare_value(self, value):
|
|
||||||
if not value:
|
|
||||||
value = ""
|
|
||||||
if isinstance(value, basestring):
|
|
||||||
pks = self.parse_tokenized_value(value)
|
|
||||||
value = self.model.objects.filter(pk__in=pks)
|
|
||||||
if isinstance(value, self.model):
|
|
||||||
value = [value]
|
|
||||||
if isinstance(value, long):
|
|
||||||
value = self.model.objects.filter(pk=value)
|
|
||||||
|
|
||||||
self.widget.attrs["data-pre"] = tokeninput_id_name_json(value)
|
|
||||||
|
|
||||||
# doing this in the constructor is difficult because the URL
|
|
||||||
# patterns may not have been fully constructed there yet
|
|
||||||
self.widget.attrs["data-ajax-url"] = urlreverse("ipr_ajax_rfc_search")
|
|
||||||
|
|
||||||
return ",".join(str(e.pk) for e in value)
|
|
||||||
|
|
||||||
class AutocompletedRfcField(AutocompletedRfcsField):
|
|
||||||
"""Version of AutocompletedEmailsField specialized to a single object."""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs["max_entries"] = 1
|
|
||||||
super(AutocompletedRfcField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self, value):
|
|
||||||
return super(AutocompletedRfcField, self).clean(value).first()
|
|
|
@ -5,9 +5,9 @@ from django.utils.safestring import mark_safe
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from ietf.group.models import Group
|
from ietf.group.models import Group
|
||||||
|
from ietf.doc.fields import SearchableDocAliasField
|
||||||
from ietf.ipr.mail import utc_from_string
|
from ietf.ipr.mail import utc_from_string
|
||||||
from ietf.ipr.fields import (AutocompletedIprDisclosuresField, AutocompletedDraftField,
|
from ietf.ipr.fields import SearchableIprDisclosuresField
|
||||||
AutocompletedRfcField)
|
|
||||||
from ietf.ipr.models import (IprDocRel, IprDisclosureBase, HolderIprDisclosure,
|
from ietf.ipr.models import (IprDocRel, IprDisclosureBase, HolderIprDisclosure,
|
||||||
GenericIprDisclosure, ThirdPartyIprDisclosure, NonDocSpecificIprDisclosure,
|
GenericIprDisclosure, ThirdPartyIprDisclosure, NonDocSpecificIprDisclosure,
|
||||||
IprLicenseTypeName, IprDisclosureStateName)
|
IprLicenseTypeName, IprDisclosureStateName)
|
||||||
|
@ -90,7 +90,7 @@ class AddEmailForm(forms.Form):
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
class DraftForm(forms.ModelForm):
|
class DraftForm(forms.ModelForm):
|
||||||
document = AutocompletedDraftField(required=False)
|
document = SearchableDocAliasField(label="I-D name/RFC number", required=False, doc_type="draft")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IprDocRel
|
model = IprDocRel
|
||||||
|
@ -103,10 +103,10 @@ class GenericDisclosureForm(forms.Form):
|
||||||
"""Custom ModelForm-like form to use for new Generic or NonDocSpecific Iprs.
|
"""Custom ModelForm-like form to use for new Generic or NonDocSpecific Iprs.
|
||||||
If patent_info is submitted create a NonDocSpecificIprDisclosure object
|
If patent_info is submitted create a NonDocSpecificIprDisclosure object
|
||||||
otherwise create a GenericIprDisclosure object."""
|
otherwise create a GenericIprDisclosure object."""
|
||||||
compliant = forms.CharField(label="This disclosure complies with RFC 3979", required=False)
|
compliant = forms.BooleanField(label="This disclosure complies with RFC 3979", required=False)
|
||||||
holder_legal_name = forms.CharField(max_length=255)
|
holder_legal_name = forms.CharField(max_length=255)
|
||||||
notes = forms.CharField(max_length=255,widget=forms.Textarea,required=False)
|
notes = forms.CharField(label="Additional notes", max_length=255,widget=forms.Textarea,required=False)
|
||||||
other_designations = forms.CharField(max_length=255,required=False)
|
other_designations = forms.CharField(label="Designations for other contributions", max_length=255,required=False)
|
||||||
holder_contact_name = forms.CharField(label="Name", max_length=255)
|
holder_contact_name = forms.CharField(label="Name", max_length=255)
|
||||||
holder_contact_email = forms.EmailField(label="Email")
|
holder_contact_email = forms.EmailField(label="Email")
|
||||||
holder_contact_info = forms.CharField(label="Other Info (address, phone, etc.)", max_length=255,widget=forms.Textarea,required=False)
|
holder_contact_info = forms.CharField(label="Other Info (address, phone, etc.)", max_length=255,widget=forms.Textarea,required=False)
|
||||||
|
@ -115,7 +115,7 @@ class GenericDisclosureForm(forms.Form):
|
||||||
patent_info = forms.CharField(max_length=255,widget=forms.Textarea, required=False, help_text="Patent, Serial, Publication, Registration, or Application/File number(s), Date(s) granted or applied for, Country, and any additional notes")
|
patent_info = forms.CharField(max_length=255,widget=forms.Textarea, required=False, help_text="Patent, Serial, Publication, Registration, or Application/File number(s), Date(s) granted or applied for, Country, and any additional notes")
|
||||||
has_patent_pending = forms.BooleanField(required=False)
|
has_patent_pending = forms.BooleanField(required=False)
|
||||||
statement = forms.CharField(max_length=255,widget=forms.Textarea,required=False)
|
statement = forms.CharField(max_length=255,widget=forms.Textarea,required=False)
|
||||||
updates = AutocompletedIprDisclosuresField(required=False)
|
updates = SearchableIprDisclosuresField(required=False, help_text="If this disclosure <strong>updates</strong> other disclosures identify here which ones. Leave this field blank if this disclosure does not update any prior disclosures. Note: Updates to IPR disclosures must only be made by authorized representatives of the original submitters. Updates will automatically be forwarded to the current Patent Holder's Contact and to the Submitter of the original IPR disclosure.")
|
||||||
same_as_ii_above = forms.BooleanField(label="Same as in section II above", required=False)
|
same_as_ii_above = forms.BooleanField(label="Same as in section II above", required=False)
|
||||||
|
|
||||||
def __init__(self,*args,**kwargs):
|
def __init__(self,*args,**kwargs):
|
||||||
|
@ -156,7 +156,7 @@ class GenericDisclosureForm(forms.Form):
|
||||||
|
|
||||||
class IprDisclosureFormBase(forms.ModelForm):
|
class IprDisclosureFormBase(forms.ModelForm):
|
||||||
"""Base form for Holder and ThirdParty disclosures"""
|
"""Base form for Holder and ThirdParty disclosures"""
|
||||||
updates = AutocompletedIprDisclosuresField(required=False, help_text=mark_safe("If this disclosure <strong>updates</strong> other disclosures identify here which ones. Leave this field blank if this disclosure does not update any prior disclosures. Note: Updates to IPR disclosures must only be made by authorized representatives of the original submitters. Updates will automatically be forwarded to the current Patent Holder's Contact and to the Submitter of the original IPR disclosure."))
|
updates = SearchableIprDisclosuresField(required=False, help_text=mark_safe("If this disclosure <strong>updates</strong> other disclosures identify here which ones. Leave this field blank if this disclosure does not update any prior disclosures. Note: Updates to IPR disclosures must only be made by authorized representatives of the original submitters. Updates will automatically be forwarded to the current Patent Holder's Contact and to the Submitter of the original IPR disclosure."))
|
||||||
same_as_ii_above = forms.BooleanField(required=False)
|
same_as_ii_above = forms.BooleanField(required=False)
|
||||||
|
|
||||||
def __init__(self,*args,**kwargs):
|
def __init__(self,*args,**kwargs):
|
||||||
|
@ -212,7 +212,7 @@ class HolderIprDisclosureForm(IprDisclosureFormBase):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super(HolderIprDisclosureForm, self).clean()
|
super(HolderIprDisclosureForm, self).clean()
|
||||||
cleaned_data = self.cleaned_data
|
cleaned_data = self.cleaned_data
|
||||||
if not self.data.get('draft-0-document') and not self.data.get('rfc-0-document') and not cleaned_data.get('other_designations'):
|
if not self.data.get('iprdocrel_set-0-document') and not cleaned_data.get('other_designations'):
|
||||||
raise forms.ValidationError('You need to specify a contribution in Section IV')
|
raise forms.ValidationError('You need to specify a contribution in Section IV')
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
@ -254,12 +254,6 @@ class NotifyForm(forms.Form):
|
||||||
type = forms.CharField(widget=forms.HiddenInput)
|
type = forms.CharField(widget=forms.HiddenInput)
|
||||||
text = forms.CharField(widget=forms.Textarea)
|
text = forms.CharField(widget=forms.Textarea)
|
||||||
|
|
||||||
class RfcForm(DraftForm):
|
|
||||||
document = AutocompletedRfcField(required=False)
|
|
||||||
|
|
||||||
class Meta(DraftForm.Meta):
|
|
||||||
exclude = ('revisions',)
|
|
||||||
|
|
||||||
class ThirdPartyIprDisclosureForm(IprDisclosureFormBase):
|
class ThirdPartyIprDisclosureForm(IprDisclosureFormBase):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ThirdPartyIprDisclosure
|
model = ThirdPartyIprDisclosure
|
||||||
|
@ -268,7 +262,7 @@ class ThirdPartyIprDisclosureForm(IprDisclosureFormBase):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super(ThirdPartyIprDisclosureForm, self).clean()
|
super(ThirdPartyIprDisclosureForm, self).clean()
|
||||||
cleaned_data = self.cleaned_data
|
cleaned_data = self.cleaned_data
|
||||||
if not self.data.get('draft-0-document') and not self.data.get('rfc-0-document') and not cleaned_data.get('other_designations'):
|
if not self.data.get('iprdocrel_set-0-document') and not cleaned_data.get('other_designations'):
|
||||||
raise forms.ValidationError('You need to specify a contribution in Section III')
|
raise forms.ValidationError('You need to specify a contribution in Section III')
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
|
|
@ -182,11 +182,11 @@ from ietf.message.models import Message
|
||||||
|
|
||||||
class IprDisclosureBase(models.Model):
|
class IprDisclosureBase(models.Model):
|
||||||
by = models.ForeignKey(Person) # who was logged in, or System if nobody was logged in
|
by = models.ForeignKey(Person) # who was logged in, or System if nobody was logged in
|
||||||
compliant = models.BooleanField(default=True) # complies to RFC3979
|
compliant = models.BooleanField("Complies to RFC3979", default=True)
|
||||||
docs = models.ManyToManyField(DocAlias, through='IprDocRel')
|
docs = models.ManyToManyField(DocAlias, through='IprDocRel')
|
||||||
holder_legal_name = models.CharField(max_length=255)
|
holder_legal_name = models.CharField(max_length=255)
|
||||||
notes = models.TextField(blank=True)
|
notes = models.TextField("Additional notes", blank=True)
|
||||||
other_designations = models.CharField(blank=True, max_length=255)
|
other_designations = models.CharField("Designations for other contributions", blank=True, max_length=255)
|
||||||
rel = models.ManyToManyField('self', through='RelatedIpr', symmetrical=False)
|
rel = models.ManyToManyField('self', through='RelatedIpr', symmetrical=False)
|
||||||
state = models.ForeignKey(IprDisclosureStateName)
|
state = models.ForeignKey(IprDisclosureStateName)
|
||||||
submitter_name = models.CharField(max_length=255)
|
submitter_name = models.CharField(max_length=255)
|
||||||
|
|
|
@ -283,13 +283,11 @@ class IprTests(TestCase):
|
||||||
"holder_contact_info": "555-555-0100",
|
"holder_contact_info": "555-555-0100",
|
||||||
"ietfer_name": "Test Participant",
|
"ietfer_name": "Test Participant",
|
||||||
"ietfer_contact_info": "555-555-0101",
|
"ietfer_contact_info": "555-555-0101",
|
||||||
"rfc-TOTAL_FORMS": 1,
|
"iprdocrel_set-TOTAL_FORMS": 2,
|
||||||
"rfc-INITIAL_FORMS": 0,
|
"iprdocrel_set-INITIAL_FORMS": 0,
|
||||||
"rfc-0-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
"iprdocrel_set-0-document": "%s" % draft.docalias_set.first().pk,
|
||||||
"draft-TOTAL_FORMS": 1,
|
"iprdocrel_set-0-revisions": '00',
|
||||||
"draft-INITIAL_FORMS": 0,
|
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||||
"draft-0-document": "%s" % draft.docalias_set.first().pk,
|
|
||||||
"draft-0-revisions": '00',
|
|
||||||
"patent_info": "none",
|
"patent_info": "none",
|
||||||
"has_patent_pending": False,
|
"has_patent_pending": False,
|
||||||
"licensing": "royalty-free",
|
"licensing": "royalty-free",
|
||||||
|
@ -319,13 +317,11 @@ class IprTests(TestCase):
|
||||||
"ietfer_name": "Test Participant",
|
"ietfer_name": "Test Participant",
|
||||||
"ietfer_contact_email": "test@ietfer.com",
|
"ietfer_contact_email": "test@ietfer.com",
|
||||||
"ietfer_contact_info": "555-555-0101",
|
"ietfer_contact_info": "555-555-0101",
|
||||||
"rfc-TOTAL_FORMS": 1,
|
"iprdocrel_set-TOTAL_FORMS": 2,
|
||||||
"rfc-INITIAL_FORMS": 0,
|
"iprdocrel_set-INITIAL_FORMS": 0,
|
||||||
"rfc-0-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
"iprdocrel_set-0-document": "%s" % draft.docalias_set.first().pk,
|
||||||
"draft-TOTAL_FORMS": 1,
|
"iprdocrel_set-0-revisions": '00',
|
||||||
"draft-INITIAL_FORMS": 0,
|
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||||
"draft-0-document": "%s" % draft.docalias_set.first().pk,
|
|
||||||
"draft-0-revisions": '00',
|
|
||||||
"patent_info": "none",
|
"patent_info": "none",
|
||||||
"has_patent_pending": False,
|
"has_patent_pending": False,
|
||||||
"licensing": "royalty-free",
|
"licensing": "royalty-free",
|
||||||
|
@ -333,7 +329,6 @@ class IprTests(TestCase):
|
||||||
"submitter_email": "test@holder.com",
|
"submitter_email": "test@holder.com",
|
||||||
})
|
})
|
||||||
self.assertEqual(r.status_code, 200)
|
self.assertEqual(r.status_code, 200)
|
||||||
# print r.content
|
|
||||||
self.assertTrue("Your IPR disclosure has been submitted" in r.content)
|
self.assertTrue("Your IPR disclosure has been submitted" in r.content)
|
||||||
|
|
||||||
iprs = IprDisclosureBase.objects.filter(title__icontains="belonging to Test Legal")
|
iprs = IprDisclosureBase.objects.filter(title__icontains="belonging to Test Legal")
|
||||||
|
@ -357,13 +352,11 @@ class IprTests(TestCase):
|
||||||
"holder_contact_info": "555-555-0100",
|
"holder_contact_info": "555-555-0100",
|
||||||
"ietfer_name": "Test Participant",
|
"ietfer_name": "Test Participant",
|
||||||
"ietfer_contact_info": "555-555-0101",
|
"ietfer_contact_info": "555-555-0101",
|
||||||
"rfc-TOTAL_FORMS": 1,
|
"iprdocrel_set-TOTAL_FORMS": 2,
|
||||||
"rfc-INITIAL_FORMS": 0,
|
"iprdocrel_set-INITIAL_FORMS": 0,
|
||||||
"rfc-0-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
"iprdocrel_set-0-document": "%s" % draft.docalias_set.first().pk,
|
||||||
"draft-TOTAL_FORMS": 1,
|
"iprdocrel_set-0-revisions": '00',
|
||||||
"draft-INITIAL_FORMS": 0,
|
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||||
"draft-0-document": "%s" % draft.docalias_set.first().pk,
|
|
||||||
"draft-0-revisions": '00',
|
|
||||||
"patent_info": "none",
|
"patent_info": "none",
|
||||||
"has_patent_pending": False,
|
"has_patent_pending": False,
|
||||||
"licensing": "royalty-free",
|
"licensing": "royalty-free",
|
||||||
|
|
|
@ -10,8 +10,6 @@ urlpatterns = patterns('ietf.ipr.views',
|
||||||
url(r'^admin/$', RedirectView.as_view(url=reverse_lazy('ipr_admin',kwargs={'state':'pending'})),name="ipr_admin_main"),
|
url(r'^admin/$', RedirectView.as_view(url=reverse_lazy('ipr_admin',kwargs={'state':'pending'})),name="ipr_admin_main"),
|
||||||
url(r'^admin/(?P<state>pending|removed|parked)/$', 'admin', name='ipr_admin'),
|
url(r'^admin/(?P<state>pending|removed|parked)/$', 'admin', name='ipr_admin'),
|
||||||
url(r'^ajax/search/$', 'ajax_search', name='ipr_ajax_search'),
|
url(r'^ajax/search/$', 'ajax_search', name='ipr_ajax_search'),
|
||||||
url(r'^ajax/draft-search/$', 'ajax_draft_search', name='ipr_ajax_draft_search'),
|
|
||||||
url(r'^ajax/rfc-search/$', 'ajax_rfc_search', name='ipr_ajax_rfc_search'),
|
|
||||||
(r'^by-draft/$', 'iprs_for_drafts_txt'),
|
(r'^by-draft/$', 'iprs_for_drafts_txt'),
|
||||||
url(r'^(?P<id>\d+)/$', 'show', name='ipr_show'),
|
url(r'^(?P<id>\d+)/$', 'show', name='ipr_show'),
|
||||||
url(r'^(?P<id>\d+)/addcomment/$', 'add_comment', name='ipr_add_comment'),
|
url(r'^(?P<id>\d+)/addcomment/$', 'add_comment', name='ipr_add_comment'),
|
||||||
|
|
|
@ -18,9 +18,9 @@ from ietf.group.models import Role, Group
|
||||||
from ietf.ietfauth.utils import role_required, has_role
|
from ietf.ietfauth.utils import role_required, has_role
|
||||||
from ietf.ipr.mail import (message_from_message, get_reply_to, get_update_submitter_emails,
|
from ietf.ipr.mail import (message_from_message, get_reply_to, get_update_submitter_emails,
|
||||||
get_update_cc_addrs)
|
get_update_cc_addrs)
|
||||||
from ietf.ipr.fields import tokeninput_id_name_json
|
from ietf.ipr.fields import select2_id_ipr_title_json
|
||||||
from ietf.ipr.forms import (HolderIprDisclosureForm, GenericDisclosureForm,
|
from ietf.ipr.forms import (HolderIprDisclosureForm, GenericDisclosureForm,
|
||||||
ThirdPartyIprDisclosureForm, DraftForm, RfcForm, SearchForm, MessageModelForm,
|
ThirdPartyIprDisclosureForm, DraftForm, SearchForm, MessageModelForm,
|
||||||
AddCommentForm, AddEmailForm, NotifyForm, StateForm, NonDocSpecificIprDisclosureForm,
|
AddCommentForm, AddEmailForm, NotifyForm, StateForm, NonDocSpecificIprDisclosureForm,
|
||||||
GenericIprDisclosureForm)
|
GenericIprDisclosureForm)
|
||||||
from ietf.ipr.models import (IprDisclosureStateName, IprDisclosureBase,
|
from ietf.ipr.models import (IprDisclosureStateName, IprDisclosureBase,
|
||||||
|
@ -173,40 +173,8 @@ def ajax_search(request):
|
||||||
|
|
||||||
objs = objs.distinct()[:10]
|
objs = objs.distinct()[:10]
|
||||||
|
|
||||||
return HttpResponse(tokeninput_id_name_json(objs), content_type='application/json')
|
return HttpResponse(select2_id_ipr_title_json(objs), content_type='application/json')
|
||||||
|
|
||||||
def ajax_draft_search(request):
|
|
||||||
q = [w.strip() for w in request.GET.get('q', '').split() if w.strip()]
|
|
||||||
|
|
||||||
if not q:
|
|
||||||
objs = DocAlias.objects.none()
|
|
||||||
else:
|
|
||||||
query = Q()
|
|
||||||
for t in q:
|
|
||||||
query &= Q(name__icontains=t)
|
|
||||||
|
|
||||||
objs = DocAlias.objects.filter(name__startswith='draft').filter(query)
|
|
||||||
|
|
||||||
objs = objs.distinct()[:10]
|
|
||||||
|
|
||||||
return HttpResponse(tokeninput_id_name_json(objs), content_type='application/json')
|
|
||||||
|
|
||||||
def ajax_rfc_search(request):
|
|
||||||
# expects one numeric term
|
|
||||||
q = [w.strip() for w in request.GET.get('q', '').split() if w.strip()]
|
|
||||||
|
|
||||||
if not q:
|
|
||||||
objs = DocAlias.objects.none()
|
|
||||||
else:
|
|
||||||
query = Q()
|
|
||||||
query &= Q(name__startswith='rfc%s' % q[0])
|
|
||||||
|
|
||||||
objs = DocAlias.objects.filter(query)
|
|
||||||
|
|
||||||
objs = objs.distinct()[:10]
|
|
||||||
|
|
||||||
return HttpResponse(tokeninput_id_name_json(objs), content_type='application/json')
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
# Views
|
# Views
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
|
@ -302,35 +270,23 @@ def edit(request, id, updates=None):
|
||||||
ipr = get_object_or_404(IprDisclosureBase, id=id).get_child()
|
ipr = get_object_or_404(IprDisclosureBase, id=id).get_child()
|
||||||
type = class_to_type[ipr.__class__.__name__]
|
type = class_to_type[ipr.__class__.__name__]
|
||||||
|
|
||||||
# only include extra when initial formset is empty
|
DraftFormset = inlineformset_factory(IprDisclosureBase, IprDocRel, form=DraftForm, can_delete=True, extra=1)
|
||||||
if ipr.iprdocrel_set.filter(document__name__startswith='draft'):
|
|
||||||
draft_extra = 0
|
|
||||||
else:
|
|
||||||
draft_extra = 1
|
|
||||||
if ipr.iprdocrel_set.filter(document__name__startswith='rfc'):
|
|
||||||
rfc_extra = 0
|
|
||||||
else:
|
|
||||||
rfc_extra = 1
|
|
||||||
DraftFormset = inlineformset_factory(IprDisclosureBase, IprDocRel, form=DraftForm, can_delete=True, extra=draft_extra)
|
|
||||||
RfcFormset = inlineformset_factory(IprDisclosureBase, IprDocRel, form=RfcForm, can_delete=True, extra=rfc_extra)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = ipr_form_mapping[ipr.__class__.__name__](request.POST,instance=ipr)
|
form = ipr_form_mapping[ipr.__class__.__name__](request.POST,instance=ipr)
|
||||||
if not type == 'generic':
|
if type != 'generic':
|
||||||
draft_formset = DraftFormset(request.POST, instance=ipr, prefix='draft')
|
draft_formset = DraftFormset(request.POST, instance=ipr)
|
||||||
rfc_formset = RfcFormset(request.POST, instance=ipr, prefix='rfc')
|
|
||||||
else:
|
else:
|
||||||
draft_formset = None
|
draft_formset = None
|
||||||
rfc_formset = None
|
|
||||||
|
|
||||||
if request.user.is_anonymous():
|
if request.user.is_anonymous():
|
||||||
person = Person.objects.get(name="(System)")
|
person = Person.objects.get(name="(System)")
|
||||||
else:
|
else:
|
||||||
person = request.user.person
|
person = request.user.person
|
||||||
|
|
||||||
# check formset validity
|
# check formset validity
|
||||||
if not type == 'generic':
|
if type != 'generic':
|
||||||
valid_formsets = draft_formset.is_valid() and rfc_formset.is_valid()
|
valid_formsets = draft_formset.is_valid()
|
||||||
else:
|
else:
|
||||||
valid_formsets = True
|
valid_formsets = True
|
||||||
|
|
||||||
|
@ -339,13 +295,9 @@ def edit(request, id, updates=None):
|
||||||
disclosure = form.save(commit=False)
|
disclosure = form.save(commit=False)
|
||||||
disclosure.save()
|
disclosure.save()
|
||||||
|
|
||||||
if not type == 'generic':
|
if type != 'generic':
|
||||||
# clear and recreate IprDocRels
|
draft_formset = DraftFormset(request.POST, instance=disclosure)
|
||||||
# IprDocRel.objects.filter(disclosure=ipr).delete()
|
|
||||||
draft_formset = DraftFormset(request.POST, instance=disclosure, prefix='draft')
|
|
||||||
draft_formset.save()
|
draft_formset.save()
|
||||||
rfc_formset = RfcFormset(request.POST, instance=disclosure, prefix='rfc')
|
|
||||||
rfc_formset.save()
|
|
||||||
|
|
||||||
set_disclosure_title(disclosure)
|
set_disclosure_title(disclosure)
|
||||||
disclosure.save()
|
disclosure.save()
|
||||||
|
@ -365,25 +317,18 @@ def edit(request, id, updates=None):
|
||||||
|
|
||||||
messages.success(request,'Disclosure modified')
|
messages.success(request,'Disclosure modified')
|
||||||
return redirect("ipr_show", id=ipr.id)
|
return redirect("ipr_show", id=ipr.id)
|
||||||
|
|
||||||
else:
|
|
||||||
# assert False, form.errors
|
|
||||||
pass
|
|
||||||
else:
|
else:
|
||||||
if ipr.updates:
|
if ipr.updates:
|
||||||
form = ipr_form_mapping[ipr.__class__.__name__](instance=ipr,initial={'updates':[ x.target for x in ipr.updates ]})
|
form = ipr_form_mapping[ipr.__class__.__name__](instance=ipr,initial={'updates':[ x.target for x in ipr.updates ]})
|
||||||
else:
|
else:
|
||||||
form = ipr_form_mapping[ipr.__class__.__name__](instance=ipr)
|
form = ipr_form_mapping[ipr.__class__.__name__](instance=ipr)
|
||||||
#disclosure = IprDisclosureBase() # dummy disclosure for inlineformset
|
#disclosure = IprDisclosureBase() # dummy disclosure for inlineformset
|
||||||
dqs=IprDocRel.objects.filter(document__name__startswith='draft')
|
draft_formset = DraftFormset(instance=ipr, queryset=IprDocRel.objects.all())
|
||||||
rqs=IprDocRel.objects.filter(document__name__startswith='rfc')
|
|
||||||
draft_formset = DraftFormset(instance=ipr, prefix='draft',queryset=dqs)
|
|
||||||
rfc_formset = RfcFormset(instance=ipr, prefix='rfc',queryset=rqs)
|
|
||||||
|
|
||||||
return render(request, "ipr/details_edit.html", {
|
return render(request, "ipr/details_edit.html", {
|
||||||
'form': form,
|
'form': form,
|
||||||
'draft_formset':draft_formset,
|
'draft_formset':draft_formset,
|
||||||
'rfc_formset':rfc_formset,
|
|
||||||
'type':type
|
'type':type
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -480,27 +425,25 @@ def iprs_for_drafts_txt(request):
|
||||||
def new(request, type, updates=None):
|
def new(request, type, updates=None):
|
||||||
"""Submit a new IPR Disclosure. If the updates field != None, this disclosure
|
"""Submit a new IPR Disclosure. If the updates field != None, this disclosure
|
||||||
updates one or more other disclosures."""
|
updates one or more other disclosures."""
|
||||||
|
|
||||||
DraftFormset = inlineformset_factory(IprDisclosureBase, IprDocRel, form=DraftForm, can_delete=False, extra=1)
|
# 1 to show initially + the template
|
||||||
RfcFormset = inlineformset_factory(IprDisclosureBase, IprDocRel, form=RfcForm, can_delete=False, extra=1)
|
DraftFormset = inlineformset_factory(IprDisclosureBase, IprDocRel, form=DraftForm, can_delete=False, extra=1 + 1)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = ipr_form_mapping[type](request.POST)
|
form = ipr_form_mapping[type](request.POST)
|
||||||
if not type == 'generic':
|
if type != 'generic':
|
||||||
draft_formset = DraftFormset(request.POST, instance=IprDisclosureBase(), prefix='draft')
|
draft_formset = DraftFormset(request.POST, instance=IprDisclosureBase())
|
||||||
rfc_formset = RfcFormset(request.POST, instance=IprDisclosureBase(), prefix='rfc')
|
|
||||||
else:
|
else:
|
||||||
draft_formset = None
|
draft_formset = None
|
||||||
rfc_formset = None
|
|
||||||
|
|
||||||
if request.user.is_anonymous():
|
if request.user.is_anonymous():
|
||||||
person = Person.objects.get(name="(System)")
|
person = Person.objects.get(name="(System)")
|
||||||
else:
|
else:
|
||||||
person = request.user.person
|
person = request.user.person
|
||||||
|
|
||||||
# check formset validity
|
# check formset validity
|
||||||
if not type == 'generic':
|
if type != 'generic':
|
||||||
valid_formsets = draft_formset.is_valid() and rfc_formset.is_valid()
|
valid_formsets = draft_formset.is_valid()
|
||||||
else:
|
else:
|
||||||
valid_formsets = True
|
valid_formsets = True
|
||||||
|
|
||||||
|
@ -511,11 +454,9 @@ def new(request, type, updates=None):
|
||||||
disclosure.state = IprDisclosureStateName.objects.get(slug='pending')
|
disclosure.state = IprDisclosureStateName.objects.get(slug='pending')
|
||||||
disclosure.save()
|
disclosure.save()
|
||||||
|
|
||||||
if not type == 'generic':
|
if type != 'generic':
|
||||||
draft_formset = DraftFormset(request.POST, instance=disclosure, prefix='draft')
|
draft_formset = DraftFormset(request.POST, instance=disclosure)
|
||||||
draft_formset.save()
|
draft_formset.save()
|
||||||
rfc_formset = RfcFormset(request.POST, instance=disclosure, prefix='rfc')
|
|
||||||
rfc_formset.save()
|
|
||||||
|
|
||||||
set_disclosure_title(disclosure)
|
set_disclosure_title(disclosure)
|
||||||
disclosure.save()
|
disclosure.save()
|
||||||
|
@ -545,13 +486,11 @@ def new(request, type, updates=None):
|
||||||
else:
|
else:
|
||||||
form = ipr_form_mapping[type]()
|
form = ipr_form_mapping[type]()
|
||||||
disclosure = IprDisclosureBase() # dummy disclosure for inlineformset
|
disclosure = IprDisclosureBase() # dummy disclosure for inlineformset
|
||||||
draft_formset = DraftFormset(instance=disclosure, prefix='draft')
|
draft_formset = DraftFormset(instance=disclosure)
|
||||||
rfc_formset = RfcFormset(instance=disclosure, prefix='rfc')
|
|
||||||
|
|
||||||
return render(request, "ipr/details_edit.html", {
|
return render(request, "ipr/details_edit.html", {
|
||||||
'form': form,
|
'form': form,
|
||||||
'draft_formset':draft_formset,
|
'draft_formset':draft_formset,
|
||||||
'rfc_formset':rfc_formset,
|
|
||||||
'type':type,
|
'type':type,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
{% extends "ietf.html" %}
|
{% extends "ietf.html" %}
|
||||||
|
|
||||||
|
{% load ietf_filters ipr_filters bootstrap3 widget_tweaks %}
|
||||||
{% load ietf_filters %}
|
|
||||||
{% load ipr_filters %}
|
|
||||||
{% load bootstrap3 %}
|
|
||||||
|
|
||||||
{% block title %}{% if form.instance %}Edit IPR #{{ form.instance.id }}{% else %}New IPR{% endif %}{% endblock %}
|
{% block title %}{% if form.instance %}Edit IPR #{{ form.instance.id }}{% else %}New IPR{% endif %}{% endblock %}
|
||||||
|
|
||||||
{% block pagehead %}
|
{% block pagehead %}
|
||||||
<link rel="stylesheet" type="text/css" href="/css/token-input.css"></link>
|
<link rel="stylesheet" href="/facelift/css/lib/select2.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/css/ipr.css"></link>
|
<link rel="stylesheet" href="/facelift/css/lib/select2-bootstrap.css">
|
||||||
|
{# <link rel="stylesheet" type="text/css" href="/css/ipr.css"></link> #}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -64,7 +62,7 @@
|
||||||
will be posted, but will be marked as "non-compliant".
|
will be posted, but will be marked as "non-compliant".
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form role="form" class="form-horizontal" method="post">
|
<form class="ipr-form form-horizontal" role="form" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
|
@ -120,41 +118,46 @@
|
||||||
If an Internet-Draft or RFC includes multiple parts and it is not
|
If an Internet-Draft or RFC includes multiple parts and it is not
|
||||||
reasonably apparent which part of such Internet-Draft or RFC is alleged
|
reasonably apparent which part of such Internet-Draft or RFC is alleged
|
||||||
to be covered by the patent information disclosed in Section
|
to be covered by the patent information disclosed in Section
|
||||||
V(A) or V(B), it is helpful if the discloser identifies the sections of
|
V(A) or V(B), please identify the sections of
|
||||||
the Internet-Draft or RFC that are alleged to be so
|
the Internet-Draft or RFC that are alleged to be so
|
||||||
covered.
|
covered.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<table id="id_contribution" class="ipr">
|
{{ draft_formset.management_form }}
|
||||||
<col width="20%">
|
|
||||||
<col width="50%">
|
|
||||||
<col width="15%">
|
|
||||||
<col width="15%">
|
|
||||||
|
|
||||||
{{ rfc_formset.management_form }}
|
|
||||||
{% for rfc in rfc_formset %}
|
|
||||||
<tr class="rfc_row">
|
|
||||||
<td class="iprlabel">RFC Name:{% if forloop.last %}<div><a id="rfc_add_link" href="javascript:void(0)">Add More</a></div>{% endif %}</td>
|
|
||||||
<td class="iprdata">{{ rfc.id }}{{ rfc.document.errors }}{{ rfc.document }}</td><td colspan="2" class="mini">{{ rfc.sections.errors }}{{ rfc.sections }}<div>Sections</div></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{{ draft_formset.management_form }}
|
|
||||||
{% for draft in draft_formset %}
|
|
||||||
<tr class="draft_row">
|
|
||||||
<td class="iprlabel">I-D Filename:{% if forloop.last %}<div><a id="draft_add_link" href="javascript:void(0)">Add More</a></div>{% endif %}</td>
|
|
||||||
<td class="iprdata">{{ draft.id }}{{ draft.document.errors }}{{ draft.document }}</td><td class="mini">{{ draft.revisions.errors }}{{ draft.revisions }}<div>Revisions</div></td><td class="mini">{{ draft.sections.errors }}{{ draft.sections }}<div>Sections</div></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<tr>
|
{% for draft_form in draft_formset %}
|
||||||
<td class="iprlabel">Designations for Other Contributions:</td>
|
<div class="form-group draft-row {% if forloop.last %}template{% endif %}">
|
||||||
<td colspan="3" class="iprdata">{{ form.other_designations.errors }} {{ form.other_designations }}</td>
|
|
||||||
</tr>
|
<label class="col-md-2 control-label" for="{{ draft_form.document.id_for_label }}">
|
||||||
</table>
|
{{ draft_form.document.label }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
{{ draft_form.id }}
|
||||||
|
{{ draft_form.document }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-2">
|
||||||
|
{% render_field draft_form.revisions class="form-control" placeholder="Revisions, e.g. 04-07" %}
|
||||||
|
<label class="sr-only" for="{{ draft_form.revisions.id_for_label }}">{{ draft_form.revisions.label }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-2">
|
||||||
|
{% render_field draft_form.sections class="form-control" placeholder="Sections" %}
|
||||||
|
<label class="sr-only" for="{{ draft_form.sections.id_for_label }}">{{ draft_form.sections.label }}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10"><a class="draft-add-row btn btn-default"><i class="glyphicon glyphicon-plus"></i> Add more</a></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% bootstrap_field form.other_designations layout='horizontal' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h2>{% cycle section %}.Disclosure of Patent Information{% if form.instance|to_class_name == "ThirdPartyIprDicslosure" %}, if known{% endif %}
|
<h2>{% cycle section %}. Disclosure of Patent Information{% if form.instance|to_class_name == "ThirdPartyIprDicslosure" %}, if known{% endif %}
|
||||||
<small>i.e., patents or patent applications required to be disclosed by Section 6 of RFC3979</small></h2>
|
<small>i.e., patents or patent applications required to be disclosed by Section 6 of RFC3979</small></h2>
|
||||||
|
|
||||||
{% if form.patent_info %}
|
{% if form.patent_info %}
|
||||||
|
@ -238,7 +241,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script type="text/javascript" src="/js/ipr-edit.js"></script>
|
<script src="/facelift/js/lib/select2-3.5.2.min.js"></script>
|
||||||
<script type="text/javascript" src="/js/lib/jquery.tokeninput.js"></script>
|
<script src="/facelift/js/lib/bootstrap-datepicker.js"></script>
|
||||||
<script type="text/javascript" src="/js/tokenized-field.js"></script>
|
<script src="/facelift/js/ipr-edit.js"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -47,8 +47,3 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% endblock %} <!-- tab_content -->
|
{% endblock %} <!-- tab_content -->
|
||||||
|
|
||||||
{% block content_end %}
|
|
||||||
<script type="text/javascript" src="/js/history.js"></script>
|
|
||||||
<script type="text/javascript" src="/js/snippet.js"></script>
|
|
||||||
{% endblock content_end %}
|
|
|
@ -247,3 +247,7 @@ pre { line-height: 1.214; }
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 5em;
|
min-width: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* IPR */
|
||||||
|
|
||||||
|
.ipr-form .draft-row.template { display: none }
|
||||||
|
|
56
static/facelift/js/ipr-edit.js
Normal file
56
static/facelift/js/ipr-edit.js
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
$(document).ready(function() {
|
||||||
|
var form = $(".ipr-form");
|
||||||
|
|
||||||
|
form.find("input[required],select[required],textarea[required]").closest(".form-group").find("label").addClass("required");
|
||||||
|
var template = form.find('.draft-row.template');
|
||||||
|
|
||||||
|
var templateData = template.clone();
|
||||||
|
|
||||||
|
$('.draft-add-row').click(function() {
|
||||||
|
var el = template.clone(true);
|
||||||
|
var totalField = $('#id_iprdocrel_set-TOTAL_FORMS');
|
||||||
|
var total = +totalField.val();
|
||||||
|
|
||||||
|
el.find(':input').each(function() {
|
||||||
|
var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
|
||||||
|
var id = 'id_' + name;
|
||||||
|
$(this).attr({'name': name, 'id': id}).val('');
|
||||||
|
});
|
||||||
|
|
||||||
|
el.find('label').each(function() {
|
||||||
|
var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
|
||||||
|
$(this).attr('for', newFor);
|
||||||
|
});
|
||||||
|
|
||||||
|
++total;
|
||||||
|
|
||||||
|
totalField.val(total);
|
||||||
|
|
||||||
|
template.before(el);
|
||||||
|
el.removeClass("template");
|
||||||
|
|
||||||
|
el.find(".select2-field").each(function () {
|
||||||
|
setupSelect2Field($(this));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateRevisions() {
|
||||||
|
var selectbox = $(this).find('[name$="document"]');
|
||||||
|
if (selectbox.val()) {
|
||||||
|
var name = selectbox.select2("data").text;
|
||||||
|
if (name.toLowerCase().substring(0, 3) == "rfc")
|
||||||
|
$(this).find('[name$=revisions]').val("").hide();
|
||||||
|
else
|
||||||
|
$(this).find('[name$=revisions]').show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.on("change", ".select2-field", function () {
|
||||||
|
$(this).closest(".draft-row").each(updateRevisions);
|
||||||
|
});
|
||||||
|
|
||||||
|
// add a little bit of delay to let the select2 box have time to do its magic
|
||||||
|
setTimeout(function () {
|
||||||
|
form.find(".draft-row").each(updateRevisions);
|
||||||
|
}, 10);
|
||||||
|
});
|
Loading…
Reference in a new issue