Clean up search views and remove dead code, port them to the new DB
schema, hack related views in iesg/ and wginfo/ to use the new search interfaces, avoid camelCase in search GET parameters (with backwards-compat fallback), add some simple search unit tests, remove caching from views_search.py index pages as they're now pretty fast to generate, rewrite ballot popup JS, regularize some CSS classes to use hyphen-notation rather than camelCase, move some of the search templates to doc/. idrfc/ now mostly contains some wrapper code still in use by other subdirs, some ported code not yet moved, and dead code. - Legacy-Id: 5611
This commit is contained in:
parent
bb7d037b3e
commit
e94d1df549
|
@ -36,6 +36,9 @@ class State(models.Model):
|
|||
class Meta:
|
||||
ordering = ["type", "order"]
|
||||
|
||||
IESG_BALLOT_ACTIVE_STATES = ("lc", "writeupw", "goaheadw", "iesg-eva", "defer")
|
||||
IESG_SUBSTATE_TAGS = ('point', 'ad-f-up', 'need-rev', 'extpty')
|
||||
|
||||
class DocumentInfo(models.Model):
|
||||
"""Any kind of document. Draft, RFC, Charter, IPR Statement, Liaison Statement"""
|
||||
time = models.DateTimeField(default=datetime.datetime.now) # should probably have auto_now=True
|
||||
|
@ -186,9 +189,7 @@ class Document(DocumentInfo):
|
|||
def get_absolute_url(self):
|
||||
name = self.name
|
||||
if self.type_id == "draft" and self.get_state_slug() == "rfc":
|
||||
aliases = self.docalias_set.filter(name__startswith="rfc")
|
||||
if aliases:
|
||||
name = aliases[0].name
|
||||
name = self.canonical_name()
|
||||
elif self.type_id in ('slides','agenda','minutes'):
|
||||
session = self.session_set.all()[0]
|
||||
meeting = session.meeting
|
||||
|
@ -248,11 +249,10 @@ class Document(DocumentInfo):
|
|||
"""Return the doc aliases that are target of relationship originating from self."""
|
||||
return DocAlias.objects.filter(relateddocument__source=self, relateddocument__relationship=relationship)
|
||||
|
||||
#TODO can/should this be a function instead of a property? Currently a view uses it as a property
|
||||
@property
|
||||
def telechat_date(self):
|
||||
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
return e.telechat_date if e else None
|
||||
def telechat_date(self, e=None):
|
||||
if not e:
|
||||
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
return e.telechat_date if e and e.telechat_date and e.telechat_date >= datetime.date.today() else None
|
||||
|
||||
def area_acronym(self):
|
||||
g = self.group
|
||||
|
@ -271,10 +271,6 @@ class Document(DocumentInfo):
|
|||
else:
|
||||
return "none"
|
||||
|
||||
def on_upcoming_agenda(self):
|
||||
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
return bool(e and e.telechat_date and e.telechat_date >= datetime.date.today())
|
||||
|
||||
def returning_item(self):
|
||||
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
return e.returning_item if e else None
|
||||
|
@ -299,56 +295,56 @@ class Document(DocumentInfo):
|
|||
return '<a href="%s">%s-%s</a>' % (self.get_absolute_url(), self.name , self.rev)
|
||||
|
||||
def rfc_number(self):
|
||||
qs = self.docalias_set.filter(name__startswith='rfc')
|
||||
return qs[0].name[3:] if qs else None
|
||||
n = self.canonical_name()
|
||||
return n[3:] if n.startswith("rfc") else None
|
||||
|
||||
def friendly_state(self):
|
||||
""" Return a concise text description of the document's current state """
|
||||
if self.type_id=='draft':
|
||||
# started_iesg_process is is how the redesigned database schema (as of May2012) captured what
|
||||
# used to be "has an IDInternal", aka *Wrapper.in_ietf_process()=True
|
||||
in_iesg_process = self.latest_event(type='started_iesg_process')
|
||||
iesg_state_summary=None
|
||||
if in_iesg_process:
|
||||
iesg_state = self.states.get(type='draft-iesg')
|
||||
""" Return a concise text description of the document's current state."""
|
||||
state = self.get_state()
|
||||
if not state:
|
||||
return "Unknown state"
|
||||
|
||||
if self.type_id == 'draft':
|
||||
iesg_state = self.get_state("draft-iesg")
|
||||
iesg_state_summary = None
|
||||
if iesg_state:
|
||||
# This knowledge about which tags are reportable IESG substate tags is duplicated in idrfc
|
||||
IESG_SUBSTATE_TAGS = ('point', 'ad-f-up', 'need-rev', 'extpty')
|
||||
iesg_substate = self.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
# There really shouldn't be more than one tag in iesg_substate, but this will do something sort-of-sensible if there is
|
||||
iesg_state_summary = iesg_state.name
|
||||
if iesg_substate:
|
||||
iesg_state_summary = iesg_state_summary + "::"+"::".join(tag.name for tag in iesg_substate)
|
||||
|
||||
if self.get_state_slug() == "rfc":
|
||||
n = self.rfc_number()
|
||||
return "<a href=\"%s\">RFC %s</a>" % (urlreverse('doc_view', kwargs=dict(name='rfc%s' % n)), n)
|
||||
elif self.get_state_slug() == "repl":
|
||||
if state.slug == "rfc":
|
||||
return "RFC %s (%s)" % (self.rfc_number(), self.std_level)
|
||||
elif state.slug == "repl":
|
||||
rs = self.related_that("replaces")
|
||||
if rs:
|
||||
return mark_safe("Replaced by " + ", ".join("<a href=\"%s\">%s</a>" % (urlreverse('doc_view', args=[name]), name) for name in rs))
|
||||
return mark_safe("Replaced by " + ", ".join("<a href=\"%s\">%s</a>" % (urlreverse('doc_view', kwargs=dict(name=name)), name) for name in rs))
|
||||
else:
|
||||
return "Replaced"
|
||||
elif self.get_state_slug() == "active":
|
||||
if in_iesg_process:
|
||||
elif state.slug == "active":
|
||||
if iesg_state:
|
||||
if iesg_state.slug == "dead":
|
||||
# Many drafts in the draft-iesg "Dead" state are not dead
|
||||
# in other state machines; they're just not currently under
|
||||
# IESG processing. Show them as "I-D Exists (IESG: Dead)" instead...
|
||||
return "I-D Exists (IESG: "+iesg_state_summary+")"
|
||||
return "I-D Exists (IESG: %s)" % iesg_state_summary
|
||||
elif iesg_state.slug == "lc":
|
||||
expiration_date = str(self.latest_event(LastCallDocEvent,type="sent_last_call").expires.date())
|
||||
return iesg_state_summary + " (ends "+expiration_date+")"
|
||||
else:
|
||||
return iesg_state_summary
|
||||
e = self.latest_event(LastCallDocEvent, type="sent_last_call")
|
||||
if e:
|
||||
return iesg_state_summary + " (ends %s)" % e.expires.date().isoformat()
|
||||
|
||||
return iesg_state_summary
|
||||
else:
|
||||
return "I-D Exists"
|
||||
else:
|
||||
if in_iesg_process and iesg_state.slug == "dead":
|
||||
return self.get_state().name +" (IESG: "+iesg_state_summary+")"
|
||||
if iesg_state and iesg_state.slug == "dead":
|
||||
return state.name + " (IESG: %s)" % iesg_state_summary
|
||||
# Expired/Withdrawn by Submitter/IETF
|
||||
return self.get_state().name
|
||||
return state.name
|
||||
else:
|
||||
return self.get_state().name
|
||||
return state.name
|
||||
|
||||
def ipr(self):
|
||||
"""Returns the IPR disclosures against this document (as a queryset over IprDocAlias)."""
|
||||
|
|
|
@ -21,6 +21,108 @@ from ietf.iesg.models import TelechatDate
|
|||
from ietf.doc.tests_conflict_review import *
|
||||
|
||||
|
||||
class SearchTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_search(self):
|
||||
draft = make_test_data()
|
||||
|
||||
base_url = urlreverse("doc_search")
|
||||
|
||||
# only show form, no search yet
|
||||
r = self.client.get(base_url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# no match
|
||||
r = self.client.get(base_url + "?activedrafts=on&name=thisisnotadocumentname")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("no documents match" in r.content.lower())
|
||||
|
||||
r = self.client.get(base_url + "?rfcs=on&name=")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("no documents match" in r.content.lower())
|
||||
|
||||
r = self.client.get(base_url + "?olddrafts=on&name=")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("no documents match" in r.content.lower())
|
||||
|
||||
# find by rfc/active/inactive
|
||||
draft.set_state(State.objects.get(type="draft", slug="rfc"))
|
||||
r = self.client.get(base_url + "?rfcs=on&name=%s" % draft.name)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
r = self.client.get(base_url + "?activedrafts=on&name=%s" % draft.name)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="expired"))
|
||||
r = self.client.get(base_url + "?olddrafts=on&name=%s" % draft.name)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
|
||||
# find by title
|
||||
r = self.client.get(base_url + "?activedrafts=on&name=%s" % draft.title.split()[0])
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by author
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=author&author=%s" % draft.authors.all()[0].person.name_parts()[1])
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by group
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=group&group=%s" % draft.group.acronym)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by area
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=area&area=%s" % draft.group.parent_id)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by area
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=area&area=%s" % draft.group.parent_id)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by AD
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=ad&ad=%s" % draft.ad_id)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by IESG state
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=state&state=%s&substate=" % draft.get_state("draft-iesg").pk)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
def test_drafts_pages(self):
|
||||
draft = make_test_data()
|
||||
|
||||
r = self.client.get(urlreverse("drafts_for_ad", kwargs=dict(name=draft.ad.full_name_as_key())))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="lc"))
|
||||
r = self.client.get(urlreverse("drafts_in_last_call"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
def test_indexes(self):
|
||||
draft = make_test_data()
|
||||
|
||||
r = self.client.get(urlreverse("index_all_drafts"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.name in r.content)
|
||||
|
||||
r = self.client.get(urlreverse("index_active_drafts"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
|
||||
class DocTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ from ietf.idtracker.models import InternetDraft, DocumentComment, BallotInfo
|
|||
from ietf.idrfc.mails import *
|
||||
from ietf.idrfc.utils import *
|
||||
|
||||
from ietf.doc.models import Document, DocEvent, LastCallDocEvent, WriteupDocEvent, save_document_in_history, State
|
||||
from ietf.doc.models import *
|
||||
from ietf.person.models import Person
|
||||
|
||||
def request_last_call(request, doc):
|
||||
|
@ -83,7 +83,7 @@ def expire_last_callREDESIGN(doc):
|
|||
prev = doc.get_state("draft-iesg")
|
||||
doc.set_state(state)
|
||||
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
|
|
@ -30,42 +30,31 @@
|
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import datetime
|
||||
|
||||
from django import template
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from ietf.idtracker.models import IDInternal, BallotInfo
|
||||
from ietf.idrfc.idrfc_wrapper import position_to_string, BALLOT_ACTIVE_STATES
|
||||
from ietf.idtracker.templatetags.ietf_filters import in_group, timesince_days
|
||||
from ietf.ietfauth.decorators import has_role
|
||||
from ietf.doc.models import BallotDocEvent, BallotPositionDocEvent
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from datetime import date
|
||||
from ietf.ietfauth.utils import user_is_person, has_role
|
||||
from ietf.doc.models import BallotDocEvent, BallotPositionDocEvent, IESG_BALLOT_ACTIVE_STATES, IESG_SUBSTATE_TAGS
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
def get_user_name(context):
|
||||
if 'user' in context and context['user'].is_authenticated():
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.person.models import Person
|
||||
try:
|
||||
return context['user'].get_profile().plain_name()
|
||||
except Person.DoesNotExist:
|
||||
return None
|
||||
|
||||
person = context['user'].get_profile().person()
|
||||
if person:
|
||||
return str(person)
|
||||
return None
|
||||
|
||||
def render_ballot_icon(user, doc):
|
||||
if not doc:
|
||||
return ""
|
||||
|
||||
# FIXME: temporary backwards-compatibility hack
|
||||
from ietf.doc.models import Document
|
||||
if not isinstance(doc, Document):
|
||||
doc = doc._draft
|
||||
|
||||
if doc.type_id == "draft":
|
||||
s = doc.get_state("draft-iesg")
|
||||
if s and s.name not in BALLOT_ACTIVE_STATES:
|
||||
if doc.get_state_slug("draft-iesg") not in IESG_BALLOT_ACTIVE_STATES:
|
||||
return ""
|
||||
elif doc.type_id == "charter":
|
||||
if doc.get_state_slug() not in ("intrev", "iesgrev"):
|
||||
|
@ -74,12 +63,10 @@ def render_ballot_icon(user, doc):
|
|||
if doc.get_state_slug() not in ("iesgeval","defer"):
|
||||
return ""
|
||||
|
||||
ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
|
||||
ballot = doc.active_ballot()
|
||||
if not ballot:
|
||||
return ""
|
||||
|
||||
edit_position_url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk))
|
||||
|
||||
def sort_key(t):
|
||||
_, pos = t
|
||||
if not pos:
|
||||
|
@ -92,11 +79,18 @@ def render_ballot_icon(user, doc):
|
|||
positions = list(doc.active_ballot().active_ad_positions().items())
|
||||
positions.sort(key=sort_key)
|
||||
|
||||
cm = ""
|
||||
edit_position_url = ""
|
||||
if has_role(user, "Area Director"):
|
||||
cm = ' oncontextmenu="editBallot(\''+str(edit_position_url)+'\');return false;"'
|
||||
edit_position_url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk))
|
||||
|
||||
res = ['<table class="ballot_icon" title="IESG Evaluation Record (click to show more, right-click to edit position)" onclick="showBallot(\'' + doc.name + '\',\'' + str(edit_position_url) + '\')"' + cm + '>']
|
||||
title = "IESG positions (click to show more%s)" % (", right-click to edit position" if edit_position_url else "")
|
||||
|
||||
res = ['<a href="%s" data-popup="%s" data-edit="%s" title="%s" class="ballot-icon"><table>' % (
|
||||
urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot_id=ballot.pk)),
|
||||
urlreverse("ietf.doc.views_doc.ballot_popup", kwargs=dict(name=doc.name, ballot_id=ballot.pk)),
|
||||
edit_position_url,
|
||||
title
|
||||
)]
|
||||
|
||||
res.append("<tr>")
|
||||
|
||||
|
@ -107,13 +101,13 @@ def render_ballot_icon(user, doc):
|
|||
|
||||
c = "position-%s" % (pos.pos.slug if pos else "norecord")
|
||||
|
||||
if hasattr(user, "get_profile") and ad == user.get_profile():
|
||||
if user_is_person(user, ad):
|
||||
c += " my"
|
||||
|
||||
res.append('<td class="%s" />' % c)
|
||||
|
||||
res.append("</tr>")
|
||||
res.append("</table>")
|
||||
res.append("</table></a>")
|
||||
|
||||
return "".join(res)
|
||||
|
||||
|
@ -122,48 +116,51 @@ class BallotIconNode(template.Node):
|
|||
self.doc_var = doc_var
|
||||
def render(self, context):
|
||||
doc = template.resolve_variable(self.doc_var, context)
|
||||
#if hasattr(doc, "_idinternal"):
|
||||
# # hack for old schema
|
||||
# doc = doc._idinternal
|
||||
return render_ballot_icon(context.get("user"), doc)
|
||||
|
||||
def do_ballot_icon(parser, token):
|
||||
try:
|
||||
tagName, docName = token.split_contents()
|
||||
tag_name, doc_name = token.split_contents()
|
||||
except ValueError:
|
||||
raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]
|
||||
return BallotIconNode(docName)
|
||||
return BallotIconNode(doc_name)
|
||||
|
||||
register.tag('ballot_icon', do_ballot_icon)
|
||||
|
||||
|
||||
@register.filter
|
||||
def my_position(doc, user):
|
||||
user_name = get_user_name({'user':user})
|
||||
if not user_name:
|
||||
return None
|
||||
if not in_group(user, "Area_Director"):
|
||||
if not has_role(user, "Area Director"):
|
||||
return None
|
||||
# FIXME: temporary backwards-compatibility hack
|
||||
from ietf.doc.models import Document
|
||||
if not isinstance(doc, Document):
|
||||
doc = doc._draft
|
||||
|
||||
ballot = doc.active_ballot()
|
||||
pos = "No Record"
|
||||
if ballot:
|
||||
changed_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad__name=user_name, ballot=ballot)
|
||||
if changed_pos:
|
||||
pos = changed_pos.pos.name;
|
||||
changed_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad__user=user, ballot=ballot)
|
||||
if changed_pos:
|
||||
pos = changed_pos.pos.name;
|
||||
return pos
|
||||
|
||||
@register.filter
|
||||
@register.filter()
|
||||
def state_age_colored(doc):
|
||||
if doc.type.slug == 'draft':
|
||||
if not doc.latest_event(type='started_iesg_process'):
|
||||
return ""
|
||||
# FIXME: temporary backwards-compatibility hack
|
||||
from ietf.doc.models import Document
|
||||
if not isinstance(doc, Document):
|
||||
doc = doc._draft
|
||||
|
||||
if doc.type_id == 'draft':
|
||||
if not doc.get_state_slug() in ["active", "rfc"]:
|
||||
# Don't show anything for expired/withdrawn/replaced drafts
|
||||
return ""
|
||||
main_state = doc.get_state('draft-iesg')
|
||||
IESG_SUBSTATE_TAGS = ('point', 'ad-f-up', 'need-rev', 'extpty')
|
||||
sub_states = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
main_state = doc.get_state_slug('draft-iesg')
|
||||
if not main_state:
|
||||
return ""
|
||||
|
||||
if main_state.slug in ["dead","watching","pub"]:
|
||||
if main_state in ["dead", "watching", "pub"]:
|
||||
return ""
|
||||
try:
|
||||
state_date = doc.docevent_set.filter(
|
||||
|
@ -178,26 +175,26 @@ def state_age_colored(doc):
|
|||
Q(desc__istartswith="IESG process started in state")
|
||||
).order_by('-time')[0].time.date()
|
||||
except IndexError:
|
||||
state_date = date(1990,1,1)
|
||||
days = timesince_days(state_date)
|
||||
state_date = datetime.date(1990,1,1)
|
||||
days = (datetime.date.today() - state_date).days
|
||||
# loosely based on
|
||||
# http://trac.tools.ietf.org/group/iesg/trac/wiki/PublishPath
|
||||
if main_state.slug == "lc":
|
||||
if main_state == "lc":
|
||||
goal1 = 30
|
||||
goal2 = 30
|
||||
elif main_state.slug == "rfcqueue":
|
||||
elif main_state == "rfcqueue":
|
||||
goal1 = 60
|
||||
goal2 = 120
|
||||
elif main_state.slug in ["lc-req", "ann"]:
|
||||
elif main_state in ["lc-req", "ann"]:
|
||||
goal1 = 4
|
||||
goal2 = 7
|
||||
elif 'need-rev' in [x.slug for x in sub_states]:
|
||||
elif 'need-rev' in [x.slug for x in doc.tags.all()]:
|
||||
goal1 = 14
|
||||
goal2 = 28
|
||||
elif main_state.slug == "pub-req":
|
||||
elif main_state == "pub-req":
|
||||
goal1 = 7
|
||||
goal2 = 14
|
||||
elif main_state.slug == "ad-eval":
|
||||
elif main_state == "ad-eval":
|
||||
goal1 = 14
|
||||
goal2 = 28
|
||||
else:
|
||||
|
@ -213,6 +210,7 @@ def state_age_colored(doc):
|
|||
title = ' title="Goal is <%d days"' % (goal1,)
|
||||
else:
|
||||
title = ''
|
||||
return '<span class="%s"%s>(for %d day%s)</span>' % (class_name,title,days,('','s')[days != 1])
|
||||
return mark_safe('<span class="%s"%s>(for %d day%s)</span>' % (
|
||||
class_name, title, days, 's' if days != 1 else ''))
|
||||
else:
|
||||
return ""
|
||||
|
|
|
@ -36,12 +36,13 @@ from ietf.doc.models import State
|
|||
from ietf.doc import views_doc
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^/?$', views_search.search_main),
|
||||
(r'^search/$', views_search.search_results),
|
||||
(r'^all/$', views_search.all),
|
||||
(r'^active/$', views_search.active),
|
||||
(r'^in-last-call/$', views_search.in_last_call),
|
||||
url(r'^ad/(?P<name>[A-Za-z0-9.-]+)/$', views_search.by_ad, name="doc_search_by_ad"),
|
||||
(r'^/?$', views_search.search),
|
||||
url(r'^search/$', views_search.search, name="doc_search"),
|
||||
url(r'^in-last-call/$', views_search.drafts_in_last_call, name="drafts_in_last_call"),
|
||||
url(r'^ad/(?P<name>[A-Za-z0-9.-]+)/$', views_search.drafts_for_ad, name="drafts_for_ad"),
|
||||
|
||||
url(r'^all/$', views_search.index_all_drafts, name="index_all_drafts"),
|
||||
url(r'^active/$', views_search.index_active_drafts, name="index_active_drafts"),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/((?P<rev>[0-9-]+)/)?$', views_doc.document_main, name="doc_view"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/history/$', views_doc.document_history, name="doc_history"),
|
||||
|
@ -51,7 +52,7 @@ urlpatterns = patterns('',
|
|||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/doc.json$', views_doc.document_json),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballotpopup/$', views_doc.ballot_for_popup),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballotpopup/(?P<ballot_id>[0-9]+)/$', views_doc.ballot_popup),
|
||||
#(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot.json$', views_doc.ballot_json), # legacy view
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/$', views_edit.change_state, name='doc_change_state'), # IESG state
|
||||
|
|
|
@ -64,12 +64,12 @@ def log_state_changed(request, doc, by, email_watch_list=True, note=''):
|
|||
return change
|
||||
|
||||
def log_state_changedREDESIGN(request, doc, by, prev_iesg_state, prev_iesg_tag):
|
||||
from ietf.doc.models import DocEvent
|
||||
from ietf.doc.models import DocEvent, IESG_SUBSTATE_TAGS
|
||||
|
||||
state = doc.get_state("draft-iesg")
|
||||
|
||||
state_name = state.name
|
||||
tags = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
if tags:
|
||||
state_name += "::" + tags[0].name
|
||||
|
||||
|
|
|
@ -420,7 +420,7 @@ def defer_ballotREDESIGN(request, name):
|
|||
prev_state = doc.friendly_state()
|
||||
if doc.type_id == 'draft':
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug='defer'))
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
@ -470,7 +470,7 @@ def undefer_ballotREDESIGN(request, name):
|
|||
prev_state = doc.friendly_state()
|
||||
if doc.type_id == 'draft':
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug='iesg-eva'))
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
@ -629,7 +629,7 @@ def lastcalltextREDESIGN(request, name):
|
|||
prev = doc.get_state("draft-iesg")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug='lc-req'))
|
||||
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
@ -1012,7 +1012,7 @@ def approve_ballotREDESIGN(request, name):
|
|||
prev = doc.get_state("draft-iesg")
|
||||
doc.set_state(new_state)
|
||||
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
@ -1097,7 +1097,7 @@ def make_last_call(request, name):
|
|||
prev = doc.get_state("draft-iesg")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug='lc'))
|
||||
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
|
|
@ -42,8 +42,6 @@ class ChangeStateForm(forms.Form):
|
|||
def change_state(request, name):
|
||||
pass
|
||||
|
||||
IESG_SUBSTATE_TAGS = ('point', 'ad-f-up', 'need-rev', 'extpty')
|
||||
|
||||
class ChangeStateFormREDESIGN(forms.Form):
|
||||
state = forms.ModelChoiceField(State.objects.filter(type="draft-iesg"), empty_label=None, required=True)
|
||||
substate = forms.ModelChoiceField(DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS), required=False)
|
||||
|
@ -70,7 +68,7 @@ def change_stateREDESIGN(request, name):
|
|||
|
||||
# tag handling is a bit awkward since the UI still works
|
||||
# as if IESG tags are a substate
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
|
||||
if next_state != prev_state or tag != prev_tag:
|
||||
|
@ -121,7 +119,7 @@ def change_stateREDESIGN(request, name):
|
|||
|
||||
else:
|
||||
state = doc.get_state("draft-iesg")
|
||||
t = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
t = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
form = ChangeStateForm(initial=dict(state=state.pk if state else None,
|
||||
substate=t[0].pk if t else None))
|
||||
|
||||
|
|
|
@ -31,28 +31,27 @@
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import re, datetime
|
||||
|
||||
from django import forms
|
||||
from django.shortcuts import render_to_response
|
||||
from django.db.models import Q
|
||||
from django.template import RequestContext
|
||||
from django.views.decorators.cache import cache_page
|
||||
from ietf.idtracker.models import IDState, IESGLogin, IDSubState, Area, InternetDraft, Rfc, IDInternal, IETFWG
|
||||
from ietf.idrfc.models import RfcIndex
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponsePermanentRedirect
|
||||
from ietf.idrfc.idrfc_wrapper import IdWrapper,RfcWrapper,IdRfcWrapper
|
||||
from ietf.utils import normalize_draftname
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.idrfc.expire import expirable_draft
|
||||
from ietf.utils import normalize_draftname
|
||||
from ietf.doc.models import *
|
||||
from ietf.person.models import *
|
||||
from ietf.group.models import *
|
||||
from ietf.ipr.models import IprDocAlias
|
||||
|
||||
class SearchForm(forms.Form):
|
||||
name = forms.CharField(required=False)
|
||||
rfcs = forms.BooleanField(required=False,initial=True)
|
||||
activeDrafts = forms.BooleanField(required=False,initial=True)
|
||||
oldDrafts = forms.BooleanField(required=False,initial=False)
|
||||
lucky = forms.BooleanField(required=False,initial=False)
|
||||
rfcs = forms.BooleanField(required=False, initial=True)
|
||||
activedrafts = forms.BooleanField(required=False, initial=True)
|
||||
olddrafts = forms.BooleanField(required=False, initial=False)
|
||||
|
||||
by = forms.ChoiceField(choices=[(x,x) for x in ('author','group','area','ad','state')], required=False, initial='wg', label='Foobar')
|
||||
author = forms.CharField(required=False)
|
||||
|
@ -60,7 +59,9 @@ class SearchForm(forms.Form):
|
|||
area = forms.ModelChoiceField(Group.objects.filter(type="area", state="active").order_by('name'), empty_label="any area", required=False)
|
||||
ad = forms.ChoiceField(choices=(), required=False)
|
||||
state = forms.ModelChoiceField(State.objects.filter(type="draft-iesg"), empty_label="any state", required=False)
|
||||
subState = forms.ChoiceField(choices=(), required=False)
|
||||
substate = forms.ChoiceField(choices=(), required=False)
|
||||
|
||||
sort = forms.ChoiceField(choices=(("document", "Document"), ("title", "Title"), ("date", "Date"), ("status", "Status"), ("ipr", "Ipr"), ("ad", "AD")), required=False, widget=forms.HiddenInput)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SearchForm, self).__init__(*args, **kwargs)
|
||||
|
@ -77,54 +78,138 @@ class SearchForm(forms.Form):
|
|||
inactive_ads.sort(key=extract_last_name)
|
||||
|
||||
self.fields['ad'].choices = c = [('', 'any AD')] + [(ad.pk, ad.plain_name()) for ad in active_ads] + [('', '------------------')] + [(ad.pk, ad.name) for ad in inactive_ads]
|
||||
self.fields['subState'].choices = [('', 'any substate'), ('0', 'no substate')] + [(n.slug, n.name) for n in DocTagName.objects.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))]
|
||||
self.fields['substate'].choices = [('', 'any substate'), ('0', 'no substate')] + [(n.slug, n.name) for n in DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS)]
|
||||
|
||||
def clean_name(self):
|
||||
value = self.cleaned_data.get('name','')
|
||||
return normalize_draftname(value)
|
||||
|
||||
def clean(self):
|
||||
q = self.cleaned_data
|
||||
# Reset query['by'] if needed
|
||||
if 'by' not in q:
|
||||
q['by'] = None
|
||||
else:
|
||||
for k in ('author','group','area','ad'):
|
||||
if (q['by'] == k) and (k not in q or not q[k]):
|
||||
if 'by' in q:
|
||||
for k in ('author', 'group', 'area', 'ad'):
|
||||
if q['by'] == k and not q.get(k):
|
||||
q['by'] = None
|
||||
if (q['by'] == 'state') and (not 'state' in q or not 'subState' in q or not (q['state'] or q['subState'])):
|
||||
if q['by'] == 'state' and not (q.get("state") or q.get('substate')):
|
||||
q['by'] = None
|
||||
# Reset other fields
|
||||
for k in ('author','group','area','ad'):
|
||||
if q['by'] != k:
|
||||
self.data[k] = ""
|
||||
for k in ('author','group', 'area', 'ad'):
|
||||
if k != q['by']:
|
||||
q[k] = ""
|
||||
if q['by'] != 'state':
|
||||
self.data['state'] = ""
|
||||
self.data['subState'] = ""
|
||||
q['state'] = ""
|
||||
q['subState'] = ""
|
||||
q['state'] = q['substate'] = None
|
||||
return q
|
||||
|
||||
def search_query(query_original, sort_by=None):
|
||||
query = dict(query_original.items())
|
||||
drafts = query['activeDrafts'] or query['oldDrafts']
|
||||
if (not drafts) and (not query['rfcs']):
|
||||
def wrap_value(v):
|
||||
return lambda: v
|
||||
|
||||
def fill_in_search_attributes(docs):
|
||||
# fill in some attributes for the search results to save some
|
||||
# hairy template code and avoid repeated SQL queries - remaining
|
||||
# queries we don't handle here are mostly implicit many-to-many
|
||||
# relations for which there is poor support in Django 1.2
|
||||
|
||||
docs_dict = dict((d.pk, d) for d in docs)
|
||||
doc_ids = docs_dict.keys()
|
||||
|
||||
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=doc_ids).values_list("document_id", "name"))
|
||||
|
||||
# latest event cache
|
||||
event_types = ("published_rfc",
|
||||
"changed_ballot_position",
|
||||
"started_iesg_process",
|
||||
"new_revision")
|
||||
for d in docs:
|
||||
d.latest_event_cache = dict()
|
||||
for e in event_types:
|
||||
d.latest_event_cache[e] = None
|
||||
|
||||
for e in DocEvent.objects.filter(doc__in=doc_ids, type__in=event_types).order_by('time'):
|
||||
docs_dict[e.doc_id].latest_event_cache[e.type] = e
|
||||
|
||||
# IPR
|
||||
for d in docs:
|
||||
d.iprs = []
|
||||
|
||||
ipr_docaliases = IprDocAlias.objects.filter(doc_alias__document__in=doc_ids).select_related('doc_alias')
|
||||
for a in ipr_docaliases:
|
||||
docs_dict[a.doc_alias.document_id].iprs.append(a)
|
||||
|
||||
# telechat date, can't do this with above query as we need to get TelechatDocEvents out
|
||||
seen = set()
|
||||
for e in TelechatDocEvent.objects.filter(doc__in=doc_ids, type="scheduled_for_telechat").order_by('-time'):
|
||||
if e.doc_id not in seen:
|
||||
d = docs_dict[e.doc_id]
|
||||
d.telechat_date = wrap_value(d.telechat_date(e))
|
||||
seen.add(e.doc_id)
|
||||
|
||||
# misc
|
||||
for d in docs:
|
||||
# emulate canonical name which is used by a lot of the utils
|
||||
d.canonical_name = wrap_value(rfc_aliases[d.pk] if d.pk in rfc_aliases else d.name)
|
||||
|
||||
if d.rfc_number() != None and d.latest_event_cache["published_rfc"]:
|
||||
d.latest_revision_date = d.latest_event_cache["published_rfc"].time
|
||||
elif d.latest_event_cache["new_revision"]:
|
||||
d.latest_revision_date = d.latest_event_cache["new_revision"].time
|
||||
else:
|
||||
d.latest_revision_date = d.time
|
||||
|
||||
if d.get_state_slug() == "rfc":
|
||||
d.search_heading = "RFCs"
|
||||
elif d.get_state_slug() == "active":
|
||||
d.search_heading = "Active Internet-Drafts"
|
||||
else:
|
||||
d.search_heading = "Old Internet-Drafts"
|
||||
|
||||
d.expirable = expirable_draft(d)
|
||||
|
||||
if d.get_state_slug() != "rfc":
|
||||
d.milestones = d.groupmilestone_set.filter(state="active").order_by("time").select_related("group")
|
||||
|
||||
|
||||
|
||||
# RFCs
|
||||
|
||||
# errata
|
||||
erratas = set(Document.objects.filter(tags="errata", name__in=rfc_aliases.keys()).distinct().values_list("name", flat=True))
|
||||
for d in docs:
|
||||
d.has_errata = d.name in erratas
|
||||
|
||||
# obsoleted/updated by
|
||||
for a in rfc_aliases:
|
||||
d = docs_dict[a]
|
||||
d.obsoleted_by_list = []
|
||||
d.updated_by_list = []
|
||||
|
||||
xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(),
|
||||
relationship__in=("obs", "updates")).select_related('target__document_id')
|
||||
rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc",
|
||||
document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name'))
|
||||
for rel in xed_by:
|
||||
d = docs_dict[rel.target.document_id]
|
||||
if rel.relationship_id == "obs":
|
||||
l = d.obsoleted_by_list
|
||||
elif rel.relationship_id == "updates":
|
||||
l = d.updated_by_list
|
||||
l.append(rel_rfc_aliases[rel.source_id].upper())
|
||||
l.sort()
|
||||
|
||||
|
||||
def retrieve_search_results(form):
|
||||
"""Takes a validated SearchForm and return the results."""
|
||||
if not form.is_valid():
|
||||
raise ValueError("SearchForm doesn't validate: %s" % form.errors)
|
||||
|
||||
query = form.cleaned_data
|
||||
|
||||
if not (query['activedrafts'] or query['olddrafts'] or query['rfcs']):
|
||||
return ([], {})
|
||||
|
||||
# Non-ASCII strings don't match anything; this check
|
||||
# is currently needed to avoid complaints from MySQL.
|
||||
# FIXME: this should be fixed with MySQL if it's still a problem?
|
||||
for k in ['name','author','group']:
|
||||
try:
|
||||
tmp = str(query.get(k, ''))
|
||||
except:
|
||||
query[k] = '*NOSUCH*'
|
||||
|
||||
# Start by search InternetDrafts
|
||||
idresults = []
|
||||
rfcresults = []
|
||||
MAX = 500
|
||||
|
||||
docs = InternetDraft.objects.all()
|
||||
docs = Document.objects.filter(type="draft")
|
||||
|
||||
# name
|
||||
if query["name"]:
|
||||
|
@ -135,9 +220,9 @@ def search_query(query_original, sort_by=None):
|
|||
allowed_states = []
|
||||
if query["rfcs"]:
|
||||
allowed_states.append("rfc")
|
||||
if query["activeDrafts"]:
|
||||
if query["activedrafts"]:
|
||||
allowed_states.append("active")
|
||||
if query["oldDrafts"]:
|
||||
if query["olddrafts"]:
|
||||
allowed_states.extend(['repl', 'expired', 'auth-rm', 'ietf-rm'])
|
||||
|
||||
docs = docs.filter(states__type="draft", states__slug__in=allowed_states)
|
||||
|
@ -145,7 +230,6 @@ def search_query(query_original, sort_by=None):
|
|||
# radio choices
|
||||
by = query["by"]
|
||||
if by == "author":
|
||||
# FIXME: this is full name, not last name as hinted in the HTML
|
||||
docs = docs.filter(authors__person__name__icontains=query["author"])
|
||||
elif by == "group":
|
||||
docs = docs.filter(group__acronym=query["group"])
|
||||
|
@ -157,66 +241,20 @@ def search_query(query_original, sort_by=None):
|
|||
elif by == "state":
|
||||
if query["state"]:
|
||||
docs = docs.filter(states=query["state"])
|
||||
if query["subState"]:
|
||||
docs = docs.filter(tags=query["subState"])
|
||||
if query["substate"]:
|
||||
docs = docs.filter(tags=query["substate"])
|
||||
|
||||
# evaluate and fill in values with aggregate queries to avoid
|
||||
# too many individual queries
|
||||
# evaluate and fill in attribute results immediately to cut down
|
||||
# the number of queries
|
||||
results = list(docs.select_related("states", "ad", "ad__person", "std_level", "intended_std_level", "group", "stream")[:MAX])
|
||||
|
||||
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[r.pk for r in results]).values_list("document_id", "name"))
|
||||
# canonical name
|
||||
for r in results:
|
||||
if r.pk in rfc_aliases:
|
||||
# lambda weirdness works around lambda binding in local for loop scope
|
||||
r.canonical_name = (lambda x: lambda: x)(rfc_aliases[r.pk])
|
||||
else:
|
||||
r.canonical_name = (lambda x: lambda: x)(r.name)
|
||||
|
||||
result_map = dict((r.pk, r) for r in results)
|
||||
|
||||
# events
|
||||
event_types = ("published_rfc",
|
||||
"changed_ballot_position",
|
||||
"started_iesg_process",
|
||||
"new_revision")
|
||||
for d in rfc_aliases.keys():
|
||||
for e in event_types:
|
||||
setattr(result_map[d], e, None)
|
||||
|
||||
for e in DocEvent.objects.filter(doc__in=rfc_aliases.keys(), type__in=event_types).order_by('-time'):
|
||||
r = result_map[e.doc_id]
|
||||
if not getattr(r, e.type):
|
||||
# sets e.g. r.published_date = e for use in proxy wrapper
|
||||
setattr(r, e.type, e)
|
||||
|
||||
# obsoleted/updated by
|
||||
for d in rfc_aliases:
|
||||
r = result_map[d]
|
||||
r.obsoleted_by_list = []
|
||||
r.updated_by_list = []
|
||||
|
||||
xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(), relationship__in=("obs", "updates")).select_related('target__document_id')
|
||||
rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name'))
|
||||
for rel in xed_by:
|
||||
r = result_map[rel.target.document_id]
|
||||
if rel.relationship_id == "obs":
|
||||
attr = "obsoleted_by_list"
|
||||
else:
|
||||
attr = "updated_by_list"
|
||||
|
||||
getattr(r, attr).append(int(rel_rfc_aliases[rel.source_id][3:]))
|
||||
|
||||
fill_in_search_attributes(results)
|
||||
|
||||
# sort
|
||||
def sort_key(d):
|
||||
res = []
|
||||
|
||||
canonical = d.canonical_name()
|
||||
if canonical.startswith('rfc'):
|
||||
rfc_num = int(canonical[3:])
|
||||
else:
|
||||
rfc_num = None
|
||||
rfc_num = d.rfc_number()
|
||||
|
||||
if rfc_num != None:
|
||||
res.append(2)
|
||||
|
@ -225,20 +263,20 @@ def search_query(query_original, sort_by=None):
|
|||
else:
|
||||
res.append(3)
|
||||
|
||||
if sort_by == "title":
|
||||
if query["sort"] == "title":
|
||||
res.append(d.title)
|
||||
elif sort_by == "date":
|
||||
res.append(str(d.revision_date or datetime.date(1990, 1, 1)))
|
||||
elif sort_by == "status":
|
||||
elif query["sort"] == "date":
|
||||
res.append(str(d.latest_revision_date))
|
||||
elif query["sort"] == "status":
|
||||
if rfc_num != None:
|
||||
res.append(rfc_num)
|
||||
res.append(int(rfc_num))
|
||||
else:
|
||||
res.append(d.get_state().order)
|
||||
elif sort_by == "ipr":
|
||||
res.append(d.name)
|
||||
elif sort_by == "ad":
|
||||
res.append(d.get_state().order if d.get_state() else None)
|
||||
elif query["sort"] == "ipr":
|
||||
res.append(len(d.iprs))
|
||||
elif query["sort"] == "ad":
|
||||
if rfc_num != None:
|
||||
res.append(rfc_num)
|
||||
res.append(int(rfc_num))
|
||||
elif d.get_state_slug() == "active":
|
||||
if d.get_state("draft-iesg"):
|
||||
res.append(d.get_state("draft-iesg").order)
|
||||
|
@ -246,153 +284,188 @@ def search_query(query_original, sort_by=None):
|
|||
res.append(0)
|
||||
else:
|
||||
if rfc_num != None:
|
||||
res.append(rfc_num)
|
||||
res.append(int(rfc_num))
|
||||
else:
|
||||
res.append(canonical)
|
||||
res.append(d.canonical_name())
|
||||
|
||||
return res
|
||||
|
||||
results.sort(key=sort_key)
|
||||
|
||||
# fill in a meta dict with some information for rendering the result table
|
||||
meta = {}
|
||||
if len(docs) == MAX:
|
||||
if len(results) == MAX:
|
||||
meta['max'] = MAX
|
||||
if query['by']:
|
||||
meta['advanced'] = True
|
||||
meta['by'] = query['by']
|
||||
meta['advanced'] = bool(query['by'])
|
||||
|
||||
# finally wrap in old wrappers
|
||||
meta['headers'] = [{'title': 'Document', 'key':'document'},
|
||||
{'title': 'Title', 'key':'title'},
|
||||
{'title': 'Date', 'key':'date'},
|
||||
{'title': 'Status', 'key':'status', 'colspan':'2'},
|
||||
{'title': 'IPR', 'key':'ipr'},
|
||||
{'title': 'Area Director', 'key':'ad'}]
|
||||
|
||||
wrapped_results = []
|
||||
for r in results:
|
||||
draft = None
|
||||
rfc = None
|
||||
if not r.name.startswith('rfc'):
|
||||
draft = IdWrapper(r)
|
||||
if r.name.startswith('rfc') or r.pk in rfc_aliases:
|
||||
rfc = RfcWrapper(r)
|
||||
wrapped_results.append(IdRfcWrapper(draft, rfc))
|
||||
if hasattr(form.data, "urlencode"): # form was fed a Django QueryDict, not local plain dict
|
||||
d = form.data.copy()
|
||||
for h in meta['headers']:
|
||||
d["sort"] = h["key"]
|
||||
h["sort_url"] = "?" + d.urlencode()
|
||||
if h['key'] == query.get('sort'):
|
||||
h['sorted'] = True
|
||||
|
||||
return (wrapped_results, meta)
|
||||
|
||||
return (results, meta)
|
||||
|
||||
def generate_query_string(request, ignore_list):
|
||||
"""Recreates the parameter string from the given request, and
|
||||
returns it as a string.
|
||||
Any parameter names present in ignore_list shall not be put
|
||||
in the result string.
|
||||
"""
|
||||
params = []
|
||||
for i in request.GET:
|
||||
if not i in ignore_list:
|
||||
params.append(i + "=" + request.GET[i])
|
||||
return "?" + "&".join(params)
|
||||
|
||||
def search_results(request):
|
||||
if len(request.REQUEST.items()) == 0:
|
||||
return search_main(request)
|
||||
form = SearchForm(dict(request.REQUEST.items()))
|
||||
if not form.is_valid():
|
||||
return HttpResponseBadRequest("form not valid?", mimetype="text/plain")
|
||||
def search(request):
|
||||
if request.GET:
|
||||
# backwards compatibility
|
||||
get_params = request.GET.copy()
|
||||
if 'activeDrafts' in request.GET:
|
||||
get_params['activedrafts'] = request.GET['activeDrafts']
|
||||
if 'oldDrafts' in request.GET:
|
||||
get_params['olddrafts'] = request.GET['oldDrafts']
|
||||
if 'subState' in request.GET:
|
||||
get_params['substate'] = request.GET['subState']
|
||||
|
||||
sort_by = None
|
||||
if "sortBy" in request.GET:
|
||||
sort_by = request.GET["sortBy"]
|
||||
form = SearchForm(get_params)
|
||||
if not form.is_valid():
|
||||
return HttpResponseBadRequest("form not valid: %s" % form.errors)
|
||||
|
||||
(results,meta) = search_query(form.cleaned_data, sort_by)
|
||||
|
||||
meta['searching'] = True
|
||||
meta['by'] = form.cleaned_data['by']
|
||||
meta['rqps'] = generate_query_string(request, ['sortBy'])
|
||||
# With a later Django we can do this from the template (incude with tag)
|
||||
# Pass the headers and their sort key names
|
||||
meta['hdrs'] = [{'htitle': 'Document', 'htype':'doc'},
|
||||
{'htitle': 'Title', 'htype':'title'},
|
||||
{'htitle': 'Date', 'htype':'date'},
|
||||
{'htitle': 'Status', 'htype':'status', 'colspan':'2'},
|
||||
{'htitle': 'IPR', 'htype':'ipr'},
|
||||
{'htitle': 'Ad', 'htype':'ad'}]
|
||||
|
||||
# Make sure we know which one is selected (for visibility later)
|
||||
if sort_by:
|
||||
for hdr in meta['hdrs']:
|
||||
if hdr['htype'] == sort_by:
|
||||
hdr['selected'] = True
|
||||
|
||||
if 'ajax' in request.REQUEST and request.REQUEST['ajax']:
|
||||
return render_to_response('idrfc/search_results.html', {'docs':results, 'meta':meta}, context_instance=RequestContext(request))
|
||||
elif form.cleaned_data['lucky'] and len(results)==1:
|
||||
doc = results[0]
|
||||
if doc.id:
|
||||
return HttpResponsePermanentRedirect(doc.id.get_absolute_url())
|
||||
else:
|
||||
return HttpResponsePermanentRedirect(doc.rfc.get_absolute_url())
|
||||
results, meta = retrieve_search_results(form)
|
||||
meta['searching'] = True
|
||||
else:
|
||||
return render_to_response('idrfc/search_main.html', {'form':form, 'docs':results,'meta':meta}, context_instance=RequestContext(request))
|
||||
|
||||
form = SearchForm()
|
||||
results = []
|
||||
meta = { 'by': None, 'advanced': False, 'searching': False }
|
||||
|
||||
def search_main(request):
|
||||
form = SearchForm()
|
||||
return render_to_response('idrfc/search_main.html', {'form':form}, context_instance=RequestContext(request))
|
||||
return render_to_response('doc/search.html',
|
||||
{'form':form, 'docs':results, 'meta':meta, 'show_add_to_list': True },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def by_ad(request, name):
|
||||
ad_id = None
|
||||
ad_name = None
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
responsible = Document.objects.values_list('ad', flat=True).distinct()
|
||||
for p in Person.objects.filter(Q(role__name__in=("pre-ad", "ad"),
|
||||
role__group__type="area",
|
||||
role__group__state="active")
|
||||
| Q(pk__in=responsible)).distinct():
|
||||
if name == p.full_name_as_key():
|
||||
ad_id = p.id
|
||||
ad_name = p.plain_name()
|
||||
break
|
||||
else:
|
||||
for i in IESGLogin.objects.filter(user_level__in=[1,2]):
|
||||
iname = str(i).lower().replace(' ','.')
|
||||
if name == iname:
|
||||
ad_id = i.id
|
||||
ad_name = str(i)
|
||||
break
|
||||
if not ad_id:
|
||||
def drafts_for_ad(request, name):
|
||||
ad = None
|
||||
responsible = Document.objects.values_list('ad', flat=True).distinct()
|
||||
for p in Person.objects.filter(Q(role__name__in=("pre-ad", "ad"),
|
||||
role__group__type="area",
|
||||
role__group__state="active")
|
||||
| Q(pk__in=responsible)).distinct():
|
||||
if name == p.full_name_as_key():
|
||||
ad = p
|
||||
break
|
||||
if not ad:
|
||||
raise Http404
|
||||
form = SearchForm({'by':'ad','ad':ad_id,
|
||||
'rfcs':'on', 'activeDrafts':'on', 'oldDrafts':'on'})
|
||||
if not form.is_valid():
|
||||
raise ValueError("form did not validate")
|
||||
(results,meta) = search_query(form.cleaned_data)
|
||||
results.sort(key=lambda obj: obj.view_sort_key_byad())
|
||||
return render_to_response('idrfc/by_ad.html', {'form':form, 'docs':results,'meta':meta, 'ad_name':ad_name}, context_instance=RequestContext(request))
|
||||
form = SearchForm({'by':'ad','ad': ad.id,
|
||||
'rfcs':'on', 'activedrafts':'on', 'olddrafts':'on',
|
||||
'sort': 'status'})
|
||||
results, meta = retrieve_search_results(form)
|
||||
|
||||
@cache_page(15*60) # 15 minutes
|
||||
def all(request):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
active = (dict(filename=n) for n in InternetDraft.objects.filter(states__type="draft", states__slug="active").order_by("name").values_list('name', flat=True))
|
||||
rfc1 = (dict(filename=d, rfc_number=int(n[3:])) for d, n in DocAlias.objects.filter(document__states__type="draft", document__states__slug="rfc", name__startswith="rfc").exclude(document__name__startswith="rfc").order_by("document__name").values_list('document__name','name').distinct())
|
||||
rfc2 = (dict(rfc_number=r, draft=None) for r in sorted(int(n[3:]) for n in Document.objects.filter(type="draft", name__startswith="rfc").values_list('name', flat=True)))
|
||||
dead = InternetDraft.objects.exclude(states__type="draft", states__slug__in=("active", "rfc")).select_related("states").order_by("name")
|
||||
else:
|
||||
active = InternetDraft.objects.all().filter(status=1).order_by("filename").values('filename')
|
||||
rfc1 = InternetDraft.objects.all().filter(status=3).order_by("filename").values('filename','rfc_number')
|
||||
rfc_numbers1 = InternetDraft.objects.all().filter(status=3).values_list('rfc_number', flat=True)
|
||||
rfc2 = RfcIndex.objects.all().exclude(rfc_number__in=rfc_numbers1).order_by('rfc_number').values('rfc_number','draft')
|
||||
dead = InternetDraft.objects.all().exclude(status__in=[1,3]).order_by("filename").select_related('status__status')
|
||||
return render_to_response('idrfc/all.html', {'active':active, 'rfc1':rfc1, 'rfc2':rfc2, 'dead':dead}, context_instance=RequestContext(request))
|
||||
for d in results:
|
||||
if d.get_state_slug() == "active":
|
||||
iesg_state = d.get_state("draft-iesg")
|
||||
if iesg_state:
|
||||
if iesg_state.slug == "dead":
|
||||
d.search_heading = "IESG Dead Internet-Drafts"
|
||||
else:
|
||||
d.search_heading = "%s Internet-Drafts" % iesg_state.name
|
||||
|
||||
@cache_page(15*60) # 15 minutes
|
||||
def active(request):
|
||||
groups = IETFWG.objects.exclude(group_acronym=1027)
|
||||
individual = IETFWG.objects.get(group_acronym=1027)
|
||||
return render_to_response("idrfc/active.html", {'groups':groups,'individual':individual}, context_instance=RequestContext(request))
|
||||
return render_to_response('doc/drafts_for_ad.html',
|
||||
{ 'form':form, 'docs':results, 'meta':meta, 'ad_name': ad.plain_name() },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def in_last_call(request):
|
||||
|
||||
lcdocs = []
|
||||
def drafts_in_last_call(request):
|
||||
lc_state = State.objects.get(type="draft-iesg", slug="lc").pk
|
||||
form = SearchForm({'by':'state','state': lc_state, 'rfcs':'on', 'activedrafts':'on'})
|
||||
results, meta = retrieve_search_results(form)
|
||||
|
||||
for p in InternetDraft.objects.all().filter(idinternal__primary_flag=1).filter(idinternal__cur_state__state='In Last Call'):
|
||||
if (p.idinternal.rfc_flag):
|
||||
lcdocs.append(IdRfcWrapper(None,RfcWrapper(p)))
|
||||
else:
|
||||
lcdocs.append(IdRfcWrapper(IdWrapper(p),None))
|
||||
return render_to_response('doc/drafts_in_last_call.html',
|
||||
{ 'form':form, 'docs':results, 'meta':meta },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
return render_to_response("idrfc/in_last_call.html", {'lcdocs':lcdocs}, context_instance=RequestContext(request))
|
||||
|
||||
def index_all_drafts(request):
|
||||
# try to be efficient since this view returns a lot of data
|
||||
categories = []
|
||||
|
||||
for s in ("active", "rfc", "expired", "repl", "auth-rm", "ietf-rm"):
|
||||
state = State.objects.get(type="draft", slug=s)
|
||||
|
||||
if state.slug == "rfc":
|
||||
heading = "RFCs"
|
||||
elif state.slug in ("ietf-rm", "auth-rm"):
|
||||
heading = "Internet-Drafts %s" % state.name
|
||||
else:
|
||||
heading = "%s Internet-Drafts" % state.name
|
||||
|
||||
draft_names = DocAlias.objects.filter(document__states=state).values_list("name", "document")
|
||||
|
||||
names = []
|
||||
names_to_skip = set()
|
||||
for name, doc in draft_names:
|
||||
sort_key = name
|
||||
if name != doc:
|
||||
if not name.startswith("rfc"):
|
||||
name, doc = doc, name
|
||||
names_to_skip.add(doc)
|
||||
|
||||
if name.startswith("rfc"):
|
||||
name = name.upper()
|
||||
sort_key = -int(name[3:])
|
||||
|
||||
names.append((name, sort_key))
|
||||
|
||||
names.sort(key=lambda t: t[1])
|
||||
|
||||
names = ['<a href="/doc/' + name + ' %s/">' + name +'</a>' for name, _ in names if name not in names_to_skip]
|
||||
|
||||
categories.append((state,
|
||||
heading,
|
||||
len(names),
|
||||
"<br>".join(names)
|
||||
))
|
||||
return render_to_response('doc/index_all_drafts.html', { "categories": categories },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def index_active_drafts(request):
|
||||
# try to be efficient since this view returns a lot of data
|
||||
|
||||
active_state = State.objects.get(type="draft", slug="active")
|
||||
|
||||
groups_dict = dict((g.id, g) for g in Group.objects.all())
|
||||
|
||||
docs_dict = dict((d["name"], d)
|
||||
for d in Document.objects.filter(states=active_state).values("name", "rev", "title", "group_id"))
|
||||
|
||||
# add latest revision time
|
||||
for time, doc_id in NewRevisionDocEvent.objects.filter(type="new_revision", doc__states=active_state).order_by('-time').values_list("time", "doc_id"):
|
||||
d = docs_dict.get(doc_id)
|
||||
if d and "rev_time" not in d:
|
||||
d["rev_time"] = time
|
||||
|
||||
# add authors
|
||||
for a in DocumentAuthor.objects.filter(document__states=active_state).order_by("order").select_related("author__person"):
|
||||
d = docs_dict.get(a.document_id)
|
||||
if d:
|
||||
if "authors" not in d:
|
||||
d["authors"] = []
|
||||
d["authors"].append(unicode(a.author.person))
|
||||
|
||||
# put docs into groups
|
||||
for d in docs_dict.itervalues():
|
||||
g = groups_dict.get(d["group_id"])
|
||||
if not g:
|
||||
continue
|
||||
|
||||
if not hasattr(g, "active_drafts"):
|
||||
g.active_drafts = []
|
||||
|
||||
g.active_drafts.append(d)
|
||||
|
||||
groups = [g for g in groups_dict.itervalues() if hasattr(g, "active_drafts")]
|
||||
groups.sort(key=lambda g: g.acronym)
|
||||
|
||||
fallback_time = datetime.datetime(1990, 1, 1)
|
||||
for g in groups:
|
||||
g.active_drafts.sort(key=lambda d: d.get("rev_time", fallback_time))
|
||||
|
||||
return render_to_response("doc/index_active_drafts.html", { 'groups': groups }, context_instance=RequestContext(request))
|
||||
|
|
|
@ -407,14 +407,6 @@ def expires_soon(x,request):
|
|||
days = 14
|
||||
return x > -days
|
||||
|
||||
@register.filter(name='greater_than')
|
||||
def greater_than(x, y):
|
||||
return x > int(y)
|
||||
|
||||
@register.filter(name='less_than')
|
||||
def less_than(x, y):
|
||||
return x < int(y)
|
||||
|
||||
@register.filter(name='equal')
|
||||
def equal(x, y):
|
||||
return str(x)==str(y)
|
||||
|
@ -469,32 +461,22 @@ def format_history_text(text):
|
|||
full = mark_safe(keep_spacing(linebreaksbr(urlize(sanitize_html(full)))))
|
||||
snippet = truncate_html_words(full, 25)
|
||||
if snippet != full:
|
||||
return mark_safe(u'<div class="snippet">%s<span class="showAll">[show all]</span></div><div style="display:none" class="full">%s</div>' % (snippet, full))
|
||||
return mark_safe(u'<div class="snippet">%s<span class="show-all">[show all]</span></div><div style="display:none" class="full">%s</div>' % (snippet, full))
|
||||
return full
|
||||
|
||||
@register.filter
|
||||
def user_roles_json(user):
|
||||
roles = {}
|
||||
if not isinstance(user, basestring) and user.is_authenticated():
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.group.models import Role
|
||||
for r in Role.objects.filter(person__user=user).select_related(depth=1):
|
||||
if r.name_id == "secr" and r.group.acronym == "secretariat":
|
||||
roles["Secretariat"] = True
|
||||
elif r.name_id == "ad" and r.group.type_id == "area" and r.group.state_id == "active":
|
||||
roles["Area Director"] = roles["Area_Director"] = True
|
||||
else:
|
||||
for g in user.groups.all():
|
||||
roles[g.name] = True
|
||||
return mark_safe(simplejson.dumps(roles))
|
||||
|
||||
@register.filter
|
||||
def textify(text):
|
||||
text = re.sub("</?b>", "*", text)
|
||||
text = re.sub("</?i>", "/", text)
|
||||
# There are probably additional conversions we should apply here
|
||||
return text
|
||||
|
||||
|
||||
@register.filter
|
||||
def state(doc, slug):
|
||||
if slug == "stream": # convenient shorthand
|
||||
slug = "%s-stream-%s" % (doc.type_id, doc.stream_id)
|
||||
return doc.get_state(slug)
|
||||
|
||||
def _test():
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
|
|
@ -505,11 +505,11 @@ class DeferUndeferTestCase(django.test.TestCase):
|
|||
self.assertEquals(len(q('form.defer')),1)
|
||||
|
||||
# defer
|
||||
self.assertEquals(doc.telechat_date,first_date)
|
||||
self.assertEquals(doc.telechat_date(), first_date)
|
||||
r = self.client.post(url,dict())
|
||||
self.assertEquals(r.status_code, 302)
|
||||
doc = Document.objects.get(name=name)
|
||||
self.assertEquals(doc.telechat_date,second_date)
|
||||
self.assertEquals(doc.telechat_date(), second_date)
|
||||
self.assertTrue(doc.returning_item())
|
||||
defer_states = dict(draft=['draft-iesg','defer'],conflrev=['conflrev','defer'])
|
||||
if doc.type_id in defer_states:
|
||||
|
@ -547,11 +547,11 @@ class DeferUndeferTestCase(django.test.TestCase):
|
|||
self.assertEquals(len(q('form.undefer')),1)
|
||||
|
||||
# undefer
|
||||
self.assertEquals(doc.telechat_date,second_date)
|
||||
self.assertEquals(doc.telechat_date(), second_date)
|
||||
r = self.client.post(url,dict())
|
||||
self.assertEquals(r.status_code, 302)
|
||||
doc = Document.objects.get(name=name)
|
||||
self.assertEquals(doc.telechat_date,first_date)
|
||||
self.assertEquals(doc.telechat_date(), first_date)
|
||||
self.assertTrue(doc.returning_item())
|
||||
undefer_states = dict(draft=['draft-iesg','iesg-eva'],conflrev=['conflrev','iesgeval'])
|
||||
if doc.type_id in undefer_states:
|
||||
|
|
|
@ -489,8 +489,7 @@ class RescheduleForm(forms.Form):
|
|||
self.fields['telechat_date'].choices = choices
|
||||
|
||||
def handle_reschedule_form(request, doc, dates):
|
||||
initial = dict(
|
||||
telechat_date=doc.telechat_date if doc.on_upcoming_agenda() else None)
|
||||
initial = dict(telechat_date=doc.telechat_date())
|
||||
|
||||
formargs = dict(telechat_dates=dates,
|
||||
prefix="%s" % doc.name,
|
||||
|
@ -525,11 +524,11 @@ def agenda_documents(request):
|
|||
i.reschedule_form = handle_reschedule_form(request, i, dates)
|
||||
|
||||
# some may have been taken off the schedule by the reschedule form
|
||||
docs = filter(lambda x: x.on_upcoming_agenda(), docs)
|
||||
|
||||
docs = [d for d in docs if d.telechat_date()]
|
||||
|
||||
telechats = []
|
||||
for date in dates:
|
||||
matches = filter(lambda x: x.telechat_date == date, docs)
|
||||
matches = filter(lambda x: x.telechat_date() == date, docs)
|
||||
res = {}
|
||||
for i in matches:
|
||||
section_key = "s" + get_doc_section(i)
|
||||
|
|
|
@ -441,7 +441,7 @@ class RFCEditorUndoTestCase(django.test.TestCase):
|
|||
self.assertEquals(draft.get_state("draft-rfceditor"), None)
|
||||
|
||||
# let's just test we can recover
|
||||
e = DeletedEvent.objects.all().order_by("-time")[0]
|
||||
e = DeletedEvent.objects.all().order_by("-time", "-id")[0]
|
||||
|
||||
e.content_type.model_class().objects.create(**json.loads(e.json))
|
||||
self.assertTrue(StateDocEvent.objects.filter(desc="First", doc=draft))
|
||||
|
|
|
@ -45,10 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% block morecss %}{% endblock %}
|
||||
</style>
|
||||
{% block pagehead %}{% endblock %}
|
||||
<script type="text/javascript">
|
||||
IETF = {};
|
||||
IETF.user_groups = {{ user|user_roles_json }};
|
||||
</script>
|
||||
{% ifnotequal server_mode "production" %}
|
||||
<link rel="icon" href="/images/ietf-dev-icon.bmp" />
|
||||
{% else %}
|
||||
|
@ -107,7 +103,6 @@ YAHOO.util.Event.onContentReady("wgs", function () {
|
|||
{% endblock %}
|
||||
//]]>
|
||||
</script>
|
||||
<script type="text/javascript" src="/js/base.js"></script>
|
||||
{% block js %}{% endblock %}
|
||||
|
||||
{% block content_end %}
|
||||
|
|
|
@ -38,16 +38,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<ul>
|
||||
<li class="sect first">Accounts</li>
|
||||
<li><a href="{% url account_index %}">{% if request.user.is_authenticated %}Manage Account{% else %}New Account{% endif %}</a></li>
|
||||
{% if user|in_group:"Area_Director" %}
|
||||
{% if user|has_role:"Area Director" %}
|
||||
<li class="sect first">AD Dashboard</li>
|
||||
<li><a href="{% url doc_search_by_ad name=user.get_profile.person.full_name_as_key %}">My Documents</a></li>
|
||||
<li><a href="{% url drafts_for_ad name=user.get_profile.full_name_as_key %}">My Documents</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.agenda_documents %}">Next Telechat</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.discusses %}">Discusses</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.milestones_needing_review %}">Milestones</a></li>
|
||||
{# FIXME: this link should be removed when the old WG Actions are completely dead #}
|
||||
<li><a href="{% url ietf.iesg.views.working_group_actions %}">Working Groups</a></li>
|
||||
{% endif %}
|
||||
{% if user|in_group:"Secretariat" %}
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<li class="sect first">Secretariat</li>
|
||||
<li><a href="/admin/iesg/telechatdate/">Telechat Dates</a></li>
|
||||
<li><a href="/admin/iesg/telechatagendaitem/">Management Items</a></li>
|
||||
|
@ -73,7 +73,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<li class="sect first">RFC Editor</li>
|
||||
<li><a href="{% url ietf.sync.views.discrepancies %}">Sync discrepancies</a></li>
|
||||
{% endif %}
|
||||
<li class="sect{% if not user|in_group:"Area_Director,Secretariat" %} first{% endif %}">Working Groups</li>
|
||||
<li class="sect{% if not user|has_role:"Area Director,Secretariat" %} first{% endif %}">Working Groups</li>
|
||||
|
||||
<li style="padding-bottom:0;"><div id="wgs" class="yuimenu"><div class="bd" style="border:0;">
|
||||
<ul class="first-of-type" style="padding:0;">
|
||||
|
@ -92,7 +92,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
<li class="sect">Drafts & RFCs</li>
|
||||
<li><a href="/doc/">Document search:</a></li>
|
||||
<li><form action="/doc/search/" method="get" style="padding-bottom:0;margin-bottom:0;"><input type="text" style="margin-left:10px; width:100px; border:1px solid #89d;" name="name" /><input type="hidden" name="activeDrafts" value="on"/><input type="hidden" name="rfcs" value="on"/></form></li>
|
||||
<li><form action="/doc/search/" method="get" style="padding-bottom:0;margin-bottom:0;"><input type="text" style="margin-left:10px; width:100px; border:1px solid #89d;" name="name" /><input type="hidden" name="activedrafts" value="on"/><input type="hidden" name="rfcs" value="on"/></form></li>
|
||||
<li><a href="{% url submit_index %}">Submit a draft</a></li>
|
||||
{% if user|in_group:"WG Chair" %}
|
||||
<li><a href="{% url submit_approvals %}">Approve a draft</a></li>
|
||||
|
|
15
ietf/templates/doc/drafts_for_ad.html
Normal file
15
ietf/templates/doc/drafts_for_ad.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Internet-Drafts and RFCs for {{ ad_name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Internet-Drafts and RFCs for {{ ad_name }}</h1>
|
||||
|
||||
{% include "idrfc/search_results.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
15
ietf/templates/doc/drafts_in_last_call.html
Normal file
15
ietf/templates/doc/drafts_in_last_call.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Internet-Drafts in IETF Last Call{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Internet-Drafts in IETF Last Call</h1>
|
||||
|
||||
{% include "idrfc/search_results.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
36
ietf/templates/doc/index_active_drafts.html
Normal file
36
ietf/templates/doc/index_active_drafts.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block morecss %}
|
||||
.contents { max-width: 50em; }
|
||||
.contents a { float: left; width: 7em; margin-right: 2em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Active Internet-Drafts{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Active Internet-Drafts</h1>
|
||||
|
||||
<p>This page lists all active Internet-Drafts, grouped by responsible
|
||||
group. For normal use, it is recommended to use the
|
||||
<a href="{% url doc_search %}">search page</a>.</p>
|
||||
|
||||
<p>There is also an <a href="{% url index_all_drafts %}">index of all
|
||||
Internet-Drafts</a> (that page also lists some machine-readable files
|
||||
for download).</p>
|
||||
|
||||
<p class="contents">
|
||||
{% for group in groups %}<a href="#{{ group.acronym }}">{{ group.acronym }}</a> {% endfor %}
|
||||
</p>
|
||||
|
||||
<div style="clear:left"></div>
|
||||
|
||||
{% for group in groups %}
|
||||
<h2 id="{{ group.acronym }}">{{ group.name }} ({{ group.acronym }})</h2>
|
||||
{% for d in group.active_drafts %}
|
||||
<p>{{ d.title }}<br>
|
||||
{% for a in d.authors %}{{ a }}{% if not forloop.last %}, {% endif %}{% endfor %}<br>
|
||||
<a href="/doc/{{ d.name }}/">{{ d.name }}-{{ d.rev }}</a> ({{ d.rev_time|date:"Y-m-d" }})</p>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
41
ietf/templates/doc/index_all_drafts.html
Normal file
41
ietf/templates/doc/index_all_drafts.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Index of all Internet-Drafts and RFCs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Index of all Internet-Drafts and RFCs</h1>
|
||||
|
||||
<p>This page lists all Internet-Drafts and RFCs. The main purpose of
|
||||
this page is to ensure all pages can be found by search engines. For
|
||||
normal use, it is recommended to use the <a href="{% url doc_search %}">search
|
||||
page</a>.</p>
|
||||
|
||||
<p>There's also an <a href="{% url index_active_drafts %}">index of
|
||||
active Internet-Drafts</a> with more information.</p>
|
||||
|
||||
<p>In addition, the following files are available for download:</p>
|
||||
<ul>
|
||||
<li><a href="http://www.ietf.org/id/1id-index.txt">Active Internet-Drafts (text)</a></li>
|
||||
<li><a href="http://www.ietf.org/id/1id-abstracts.txt">Active Internet-Drafts with abstracts (text)</a></li>
|
||||
<li><a href="http://www.ietf.org/id/all_id2.txt">All Internet-Drafts (tab-separated)</a>, <a href="http://www.ietf.org/id/all_id.txt">older version (with fewer fields)</a></li>
|
||||
<li><a href="http://www.rfc-editor.org/rfc/rfc-index.txt">All RFCs (text)</a></li>
|
||||
<li><a href="http://www.rfc-editor.org/rfc/rfc-index.xml">All RFCs (XML)</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
|
||||
<p>The documents are listed in the following categories:</p>
|
||||
|
||||
<ul>
|
||||
{% for state, heading, count, _ in categories %}
|
||||
<li><a href="#{{ state.slug }}">{{ heading }} ({{ count }})</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% for state, heading, count, links in categories %}
|
||||
<h3 id="{{ state.slug }}">{{ heading }} ({{ count }})</h3>
|
||||
|
||||
<p class="links">{{ links|safe }}</p>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
19
ietf/templates/doc/search.html
Normal file
19
ietf/templates/doc/search.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Search Internet-Drafts and RFCs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Search Internet-Drafts and RFCs</h1>
|
||||
|
||||
<div class="ietf-box search-form-box">
|
||||
{% include "idrfc/search_form.html" %}
|
||||
</div>
|
||||
|
||||
{% if meta.searching %}{% include "idrfc/search_results.html" %}{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
|
@ -1,54 +1,46 @@
|
|||
{% comment %}
|
||||
Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of the Nokia Corporation and/or its
|
||||
subsidiary(-ies) nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endcomment %}
|
||||
{% load ietf_filters ietf_streams_redesign %}{% load ballot_icon_redesign %}{% load doc_states %}
|
||||
{% load ietf_filters %}{% load ballot_icon_redesign %}
|
||||
<td class="status">
|
||||
{{ doc.friendly_state|safe }} {% if not doc.rfc %}{{ doc|state_age_colored|safe }}{% endif %}
|
||||
{% if not hide_telechat_date %}{% if doc.telechat_date %}<br/>IESG Telechat: {{ doc.telechat_date }}{% endif %}{% endif %}
|
||||
{{ doc.friendly_state|safe }} {% if not doc.get_state_slug == "rfc" %}{{ doc|state_age_colored }}{% endif %}
|
||||
|
||||
{% block extra_status %}{% endblock %}
|
||||
{% if doc.rfc %}
|
||||
{%comment%}
|
||||
TODO: Port this block to Document when something that shows RFCs uses this template
|
||||
{% if doc.rfc.obsoleted_by %}<br />Obsoleted by {{ doc.rfc.obsoleted_by|urlize_ietf_docs }}{%endif %}
|
||||
{% if doc.rfc.updated_by %}<br />Updated by {{ doc.rfc.updated_by|urlize_ietf_docs }}{%endif %}
|
||||
{% if doc.rfc.has_errata %}<br /><a href="http://www.rfc-editor.org/errata_search.php?rfc={{doc.rfc.rfc_number}}" rel="nofollow">Errata</a>{% endif %}
|
||||
{%endcomment%}
|
||||
{% else %}{# not rfc #}
|
||||
{% if doc|rfc_editor_state %}<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{doc.name}}">{{ doc|rfc_editor_state|escape }}</a>{% endif %}
|
||||
{% stream_state doc %}
|
||||
{% endif %}
|
||||
{% if not hide_telechat_date and doc.telechat_date %}
|
||||
<br/>IESG Telechat: {{ doc.telechat_date }}
|
||||
{% endif %}
|
||||
|
||||
{% block extra_status %}{% endblock %}
|
||||
|
||||
|
||||
{% if doc.get_state_slug != "rfc" %}{# I-D #}
|
||||
|
||||
{% if doc|state:"draft-rfceditor" %}
|
||||
<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{ doc.name }}">{{ doc|state:"draft-rfceditor" }}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.stream %}
|
||||
<br />
|
||||
{% if doc|state:"stream" %}{{ doc|state:"stream" }}{% else %}{{ doc.stream }}{% endif %}
|
||||
|
||||
{% if doc.milestones %}
|
||||
{% for m in doc.milestones %}<span title="Part of {{ m.group.acronym }} milestone: {{ m.desc }}" class="milestone">{{ m.due|date:"M Y" }}</span>{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}{# RFC #}
|
||||
|
||||
{% if doc.obsoleted_by_list %}
|
||||
<div>Obsoleted by {{ doc.obsoleted_by_list|join:", "|urlize_ietf_docs }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.updated_by_list %}
|
||||
<div class="updated-by">Updated by {{ doc.updated_by_list|join:", "|urlize_ietf_docs }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.has_errata %}
|
||||
<div><a href="http://www.rfc-editor.org/errata_search.php?rfc={{ doc.rfc_number }}" rel="nofollow">Errata</a></div>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="ballot">
|
||||
{% ballot_icon doc %}
|
||||
{% ballot_icon doc %}
|
||||
</td>
|
||||
|
|
|
@ -58,7 +58,7 @@ the <a href="/doc/">search page</a> instead.</p>
|
|||
<p><a href="/doc/active/">More information about active Internet-Drafts</a></p>
|
||||
|
||||
<p>
|
||||
{% for doc in active %}<a href="/doc/{{ doc.filename }}/">{{ doc.filename }}</a><br/>
|
||||
{% for doc in active %}<a href="/doc/{{ doc.filename }}/">{{ doc.filename }}</a><br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ td.ietf-main-intro { width:200px; background:#fff5df; padding:8px; border:1px so
|
|||
The IETF Datatracker is the IETF's web system for managing information
|
||||
about:
|
||||
<ul>
|
||||
<li><a href="/doc/">Internet-Drafts and RFCs</a></li>
|
||||
<li><a href="{% url doc_search %}">Internet-Drafts and RFCs</a></li>
|
||||
<li><a href="/ipr/">IPR disclosures</a></li>
|
||||
<li><a href="/liaison/">Liaison statements</a></li>
|
||||
<li><a href="/meeting/agenda/">Meeting agenda</a> and <a href="/meeting/">session agendas/slides/minutes</a></li>
|
||||
|
@ -70,14 +70,9 @@ about:
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="search_results" style="margin-top:8px;">
|
||||
{% if docs %}
|
||||
{% include "idrfc/search_results.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -32,7 +32,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endcomment %}
|
||||
|
||||
<form id="search_form" class="search_form" action="/doc/search/" method="get">
|
||||
<form id="search_form" class="search_form" action="{% url doc_search %}" method="get">
|
||||
|
||||
<div class="search_field">
|
||||
<label>Name/number/title:</label> {{ form.name }}
|
||||
|
@ -42,18 +42,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<label>Types:</label>
|
||||
<table id="search_types">
|
||||
<tr><td><label>{{ form.rfcs }} RFCs</label></td></tr>
|
||||
<tr><td><label>{{ form.activeDrafts }} Internet-Drafts (active)</label></td></tr>
|
||||
<tr><td><label>{{ form.oldDrafts }} Internet-Drafts (expired/replaced/withdrawn)</label></td></tr>
|
||||
<tr><td><label>{{ form.activedrafts }} Internet-Drafts (active)</label></td></tr>
|
||||
<tr><td><label>{{ form.olddrafts }} Internet-Drafts (expired/replaced/withdrawn)</label></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{ form.sort }} {# hidden field #}
|
||||
|
||||
<b class="toggle_advanced"><img src="/images/{% if meta.advanced %}minus{% else %}plus{% endif %}.png" alt="" /> Advanced</b>
|
||||
|
||||
<div id="search_advanced" style="{% if not meta.advanced %}display:none;{%endif%}">
|
||||
Additional search criteria:
|
||||
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="author" {% if meta.by == "author" %}checked="checked"{% endif %}/> Author (last name):</label> {{ form.author }}
|
||||
<label><input type="radio" class="radio" name="by" value="author" {% if meta.by == "author" %}checked="checked"{% endif %}/> Author:</label> {{ form.author }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="group" {% if meta.by == "group" %}checked="checked"{% endif %}/> WG:</label> {{ form.group }}
|
||||
|
@ -65,7 +67,7 @@ Additional search criteria:
|
|||
<label><input type="radio" class="radio" name="by" value="ad" {% if meta.by == "ad" %}checked="checked"{% endif %}/> Responsible AD:</label> {{ form.ad }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="state" {% if meta.by == "state" %}checked="checked"{% endif %}/> IESG State:</label> {{ form.state }} :: {{ form.subState }}
|
||||
<label><input type="radio" class="radio" name="by" value="state" {% if meta.by == "state" %}checked="checked"{% endif %}/> IESG State:</label> {{ form.state }} :: {{ form.substate }}
|
||||
</div>
|
||||
|
||||
</div><!-- end of advanced -->
|
||||
|
|
|
@ -42,13 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% include "idrfc/search_form.html" %}
|
||||
</div>
|
||||
|
||||
<div id="search_results">
|
||||
<div id="search-results">
|
||||
{% if meta.searching %}
|
||||
{% include "idrfc/search_results.html" %}
|
||||
{% include "idrfc/search-results.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -37,28 +37,39 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
|
||||
{% if show_add_to_list and user.is_authenticated %}
|
||||
<td class="addtolist">
|
||||
{% if doc.id %}
|
||||
<a href="{% url community_add_document doc.id.draft_name %}" title="Add to your personal ID list"><img src="/images/add_to_list.png" alt="Add to your personal ID list" /></a>
|
||||
{% else %}
|
||||
<a href="{% url community_add_document doc.rfc.filename %}" title="Add to your personal ID list"><img src="/images/add_to_list.png" alt="Add to your personal ID list" /></a>
|
||||
{% endif %}
|
||||
<a href="{% url community_add_document doc.name %}" title="Add to your personal ID list"><img src="/images/add_to_list.png" alt="Add to your personal ID list" /></a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="doc">
|
||||
{% if doc.rfc %}{{ doc.rfc.displayname_with_link|safe }}
|
||||
{% if doc.id %}<br />(<a href="{{ doc.id.get_absolute_url }}">{{doc.id.draft_name}}</a>){%endif%}
|
||||
{% else %}{{ doc.id.displayname_with_link|safe }}
|
||||
{% endif %}
|
||||
<a href="{{ doc.get_absolute_url }}">{% if doc.get_state_slug == "rfc" %}RFC {{ doc.rfc_number }}{% else %}{{ doc.name }}-{{ doc.rev }}{% endif %}</a>
|
||||
|
||||
{% if doc.get_state_slug == "rfc" and "draft" in doc.name %}
|
||||
<br/><i>(was {{ doc.name }})</i>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="title">{{ doc.title }}</td>
|
||||
|
||||
<td class="date">{% if not doc.rfc %}{{ doc.publication_date }}{% else %}{{ doc.publication_date|date:"Y-m" }}{% endif %}
|
||||
{% if doc.publication_date|timesince_days|new_enough:request %}<br/><span class="ietf-small ietf-highlight-y">{% if not doc.rfc%}<a href="http:{{rfcdiff_prefix}}?url2={{doc.id.draft_name_and_revision}}">new</a>{%else%}new{%endif%}</span>{%endif%}
|
||||
{% if doc.id and doc.id.expected_expiration_date and doc.id.expected_expiration_date|timesince_days|expires_soon:request %}<br/><span class="ietf-small ietf-highlight-y">expires soon</span>{%endif%}
|
||||
<td class="date">
|
||||
{% if doc.get_state_slug == "rfc" %}{{ doc.latest_revision_date|date:"Y-m" }}{% else %}{{ doc.latest_revision_date|date:"Y-m-d" }}{% endif %}
|
||||
|
||||
{% if doc.latest_revision_date|timesince_days|new_enough:request %}
|
||||
<div class="ietf-small ietf-highlight-y"><a{% if doc.get_state_slug != "rfc" %} href="http:{{ rfcdiff_prefix }}?url2={{ doc.name }}-{{ doc.rev }}"{% endif %}>new</a></div>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.get_state_slug == "active" and doc.expirable and doc.expires|timesince_days|expires_soon:request %}
|
||||
<div class="ietf-small ietf-highlight-y">expires soon</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
{% include "idrfc/status_columns.html" %}
|
||||
{% include "idrfc/ipr_column.html" %}
|
||||
{# <td class="ad">{% if doc.ad_name %}{{ doc.ad_name }}{% else %} {% endif %}</td> #}
|
||||
<td class="ad">{{ doc.ad_name|default:"" }}</td>
|
||||
{% include "doc/status_columns.html" %}
|
||||
|
||||
<td class="ipr">
|
||||
{% if doc.iprs %}
|
||||
<a href="{% url ipr_search %}?option=document_search&id={{ doc.name }}">{{ doc.iprs|length }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="ad">{{ doc.ad|default:"" }}</td>
|
||||
|
||||
</tr>
|
||||
|
|
|
@ -32,36 +32,42 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endcomment %}
|
||||
|
||||
{% if meta.max %}
|
||||
<p><b>Too many documents match the query! Returning partial result only.</b></p>
|
||||
{% endif %}
|
||||
<div class="search-results">
|
||||
|
||||
{% if not docs %}
|
||||
<p><b>No documents match your query.</b></p>
|
||||
<h2>No documents match your query.</h2>
|
||||
{% else %}
|
||||
|
||||
{% if meta.max %}
|
||||
<h2>Too many documents match the query! Returning partial result only.</h2>
|
||||
{% endif %}
|
||||
|
||||
<table class="ietf-table ietf-doctable">
|
||||
<tr>
|
||||
{% if user.is_authenticated %}<th></th>{% endif %}
|
||||
{% if show_add_to_list and user.is_authenticated %}<th></th>{% endif %}
|
||||
|
||||
{% for hdr in meta.hdrs %}
|
||||
<th class="{{ hdr.htype }}" {% if hdr.colspan %}colspan="{{ hdr.colspan }}"{% endif %}>
|
||||
{{ hdr.htitle }}
|
||||
|
||||
<a href="{{ meta.rqps }}&sortBy={{hdr.htype}}"><img src="/images/sort-header-{% if hdr.selected %}filled{% else %}clear{% endif %}.png"/></a>
|
||||
{% for h in meta.headers %}
|
||||
<th class="{{ h.key }}" {% if h.colspan %}colspan="{{ h.colspan }}"{% endif %}>
|
||||
{% if "sort_url" in h %}
|
||||
<a href="{{ h.sort_url }}">{{ h.title }}
|
||||
<img src="/images/sort-header-{% if h.sorted %}filled{% else %}clear{% endif %}.png"/></a>
|
||||
{% else %}
|
||||
{{ h.title }}
|
||||
{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
<!-- <tr><th></th><th class="doc">Document</th><th class="title">Title</th><th class="date">Date</th><th class="status" colspan="2">Status</th><th class="ad">Area Director</th></tr> -->
|
||||
{% regroup docs by view_sort_group as grouped_docs %}
|
||||
|
||||
{% regroup docs by search_heading as grouped_docs %}
|
||||
|
||||
{% for doc_group in grouped_docs %}
|
||||
<tr class="header"><td colspan="7">{{ doc_group.grouper }}s</td></tr>
|
||||
|
||||
{% with 1 as show_add_to_list %}
|
||||
{% for doc in doc_group.list %}
|
||||
{% include "idrfc/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
<tr class="header"><td colspan="10">{{ doc_group.grouper }}</td></tr>
|
||||
|
||||
{% for doc in doc_group.list %}
|
||||
{% include "idrfc/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -31,7 +31,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endcomment %}
|
||||
{% load ietf_filters ietf_streams %}{% load ballot_icon %}
|
||||
{% load ietf_filters ietf_streams %}{% load ballot_icon_redesign %}
|
||||
<td class="status">
|
||||
{{ doc.friendly_state|safe }} {% if not doc.rfc %}{{ doc.id|state_age_colored|safe }}{% endif %}
|
||||
{% if not hide_telechat_date %}{% if doc.telechat_date %}<br/>IESG Telechat: {{ doc.telechat_date }}{% endif %}{% endif %}
|
||||
|
|
|
@ -110,3 +110,8 @@ div.agenda-wg { margin-left: 30px; margin-top:0.5em; margin-bottom: 0.5em; width
|
|||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -155,5 +155,7 @@ font-size:80%; font-style:italic;
|
|||
{% endblock content %}
|
||||
|
||||
{% block content_end %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
<script type="text/javascript" src="/js/agenda-documents.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -112,3 +112,8 @@ if (url[1] == 'byme') {
|
|||
}
|
||||
{% endif %}{# user in_group #}
|
||||
{% endblock scripts %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
{% block content %}
|
||||
{% load ietf_filters %}
|
||||
{% load ballot_icon %}
|
||||
|
||||
<h1>Bofs</h1>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
{% block content %}
|
||||
{% load ietf_filters %}
|
||||
{% load ballot_icon %}
|
||||
{% load ballot_icon_redesign %}
|
||||
|
||||
<h1>Chartering or Re-Chartering Working Groups</h1>
|
||||
|
||||
|
@ -51,3 +51,8 @@
|
|||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -35,34 +35,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% block wg_titledetail %}Documents{% endblock %}
|
||||
|
||||
{% block wg_content %}
|
||||
<div class="group-documents">
|
||||
|
||||
{% regroup docs by view_sort_group as grouped_docs %}
|
||||
{% include "idrfc/search_results.html" %}
|
||||
|
||||
<table class="ietf-table ietf-doctable" style="margin-top:16px;">
|
||||
<tr><th class="doc">Document</th><th class="title">Title</th><th class="date">Date</th><th class="status" colspan="2">Status</th><th class="ipr">ipr</th><th class="ad">Area Director</th></tr>
|
||||
{% for doc_group in grouped_docs %}
|
||||
<tr class="header"><td colspan="7">{{doc_group.grouper}}s</td></tr>
|
||||
|
||||
{% for doc in doc_group.list %}
|
||||
{% include "idrfc/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% regroup docs_related by view_sort_group as grouped_docs_related %}
|
||||
|
||||
<table class="ietf-table ietf-doctable" style="margin-top:16px;">
|
||||
<tr><th class="doc">Related Documents</th><th class="title">Title</th><th class="date">Date</th><th class="status" colspan="2">Status</th><th class="ipr">ipr</th><th class="ad">Area Director</th></tr>
|
||||
{% for doc_group in grouped_docs_related %}
|
||||
<tr class="header"><td colspan="7">{{doc_group.grouper}}s</td></tr>
|
||||
|
||||
{% for doc in doc_group.list %}
|
||||
{% include "idrfc/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% with docs_related as docs %}{% include "idrfc/search_results.html" %}{% endwith %}
|
||||
|
||||
</div>
|
||||
{% endblock wg_content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -38,7 +38,7 @@ from django.http import HttpResponse
|
|||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from ietf.idtracker.models import Area, IETFWG
|
||||
from ietf.idrfc.views_search import SearchForm, search_query
|
||||
from ietf.idrfc.views_search import SearchForm, retrieve_search_results
|
||||
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper
|
||||
from ietf.ipr.models import IprDetail
|
||||
from ietf.group.models import Group
|
||||
|
@ -145,39 +145,34 @@ def wg_documents(request, acronym):
|
|||
concluded = wg.status_id in [ 2, 3, ]
|
||||
proposed = (wg.status_id == 4)
|
||||
form = SearchForm({'by':'group', 'group':str(wg.group_acronym.acronym),
|
||||
'rfcs':'on', 'activeDrafts':'on'})
|
||||
if not form.is_valid():
|
||||
raise ValueError("form did not validate")
|
||||
(docs,meta) = search_query(form.cleaned_data)
|
||||
'rfcs':'on', 'activedrafts':'on'})
|
||||
docs, meta = retrieve_search_results(form)
|
||||
|
||||
# get the related docs
|
||||
form_related = SearchForm({'by':'group', 'name':'-'+str(wg.group_acronym.acronym)+'-', 'activeDrafts':'on'})
|
||||
if not form_related.is_valid():
|
||||
raise ValueError("form_related did not validate")
|
||||
(docs_related,meta_related) = search_query(form_related.cleaned_data)
|
||||
form_related = SearchForm({'by':'group', 'name':'-'+str(wg.group_acronym.acronym)+'-', 'activedrafts':'on'})
|
||||
docs_related, meta_related = retrieve_search_results(form_related)
|
||||
docs_related_pruned = []
|
||||
for d in docs_related:
|
||||
parts = d.id.draft_name.split("-", 2);
|
||||
parts = d.name.split("-", 2);
|
||||
# canonical form draft-<name|ietf>-wg-etc
|
||||
if ( len(parts) >= 3):
|
||||
if parts[1] != "ietf" and parts[2].startswith(wg.group_acronym.acronym+"-"):
|
||||
if len(parts) >= 3 and parts[1] != "ietf" and parts[2].startswith(wg.group_acronym.acronym + "-"):
|
||||
docs_related_pruned.append(d)
|
||||
|
||||
docs_related = docs_related_pruned
|
||||
|
||||
# move call for WG adoption to related
|
||||
cleaned_docs = []
|
||||
related_doc_names = set(d.id.draft_name for d in docs_related)
|
||||
docs_related_names = set(d.name for d in docs_related)
|
||||
for d in docs:
|
||||
if d.id and d.id._draft and d.id._draft.stream_id == "ietf" and d.id._draft.get_state_slug("draft-stream-ietf") == "c-adopt":
|
||||
if d.id.draft_name not in related_doc_names:
|
||||
if d.stream_id == "ietf" and d.get_state_slug("draft-stream-ietf") == "c-adopt":
|
||||
if d.name not in docs_related_names:
|
||||
docs_related.append(d)
|
||||
else:
|
||||
cleaned_docs.append(d)
|
||||
|
||||
docs = cleaned_docs
|
||||
|
||||
docs_related.sort(key=lambda d: d.id.draft_name)
|
||||
docs_related.sort(key=lambda d: d.name)
|
||||
|
||||
return wg, concluded, proposed, docs, meta, docs_related, meta_related
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
*/
|
||||
|
||||
body { margin: 0; }
|
||||
|
||||
a img { border: 0; }
|
||||
|
||||
.yui-skin-sam h1 {margin: 0.5em 0; font-size: 167%;}
|
||||
.yui-skin-sam .yui-navset .yui-content {
|
||||
background: white;
|
||||
|
@ -114,7 +117,8 @@ table.ietf-table { border-collapse:collapse; border:1px solid #7f7f7f; }
|
|||
.ietf-doctable tr.header { border-top: 1px solid #7f7f7f; border-bottom: 1px solid #7f7f7f; border-left: 1px solid white; border-right:2px solid white;}
|
||||
.ietf-doctable tr.header td {padding: 6px 6px; font-weight: bold; }
|
||||
.ietf-doctable table { max-width: 1200px; }
|
||||
.ietf-doctable th { cursor: pointer; white-space: nowrap; }
|
||||
.ietf-doctable th { white-space: nowrap; }
|
||||
.ietf-doctable th a { text-decoration: none; color: #fff; }
|
||||
.ietf-doctable th img { border-style: none; vertical-align: top; }
|
||||
.ietf-doctable th.doc, .ietf-doctable td.doc { min-width:20em; max-width: 35em; }
|
||||
.ietf-doctable th.title, .ietf-doctable td.title { min-width: 20em; max-width: 35em; }
|
||||
|
@ -123,17 +127,19 @@ table.ietf-table { border-collapse:collapse; border:1px solid #7f7f7f; }
|
|||
.ietf-doctable th.ipr { font-variant: small-caps; }
|
||||
.ietf-doctable th.ad, .ietf-doctable td.ad { white-space:nowrap; min-width: 6em; }
|
||||
.ietf-doctable td.ballot { border-left: hidden; min-width: 37px; }
|
||||
.ietf-doctable td .updated-by { max-width: 20em; } /* some RFCs have really long lists */
|
||||
|
||||
table.ballot_icon { empty-cells: show; padding: 0; border-spacing: 0; border: 1px solid black; border-collapse: collapse; table-layout:fixed; min-width:35px; background:white; }
|
||||
table.ballot_icon td { border: 1px solid black; height: 7px; width: 6px; padding: 0;}
|
||||
table.ballot_icon td.my { border: 3px outset black;}
|
||||
.ietf-doctable .status .milestone,
|
||||
.ietf-box .stream-state .milestone
|
||||
{ display: inline-block; font-size: smaller; background-color: #d5dde6; padding: 0 0.2em; margin-left: 0.3em; }
|
||||
|
||||
.ietf-small { font-size:85%; }
|
||||
.ietf-highlight-y { padding:0 2px;background:yellow;}
|
||||
.ietf-highlight-r { padding:0 2px;background:#ffa0a0;}
|
||||
.ietf-divider { background: #2647a0; color: white; font-size:116%; padding:0.5em 1em; }
|
||||
|
||||
table.history .snippet .showAll { color: blue; cursor: pointer; }
|
||||
|
||||
table.history .snippet .show-all { color: blue; cursor: pointer; }
|
||||
|
||||
.error-text {
|
||||
font-size: 1.095em;
|
||||
|
@ -174,14 +180,18 @@ form table .help {
|
|||
.warning { color: #a00; }
|
||||
|
||||
.position-discuss,
|
||||
.position-block { background-color: #c00000;}
|
||||
.position-yes { background-color: #80ff80;}
|
||||
.position-noobj { background-color: #80ff80;}
|
||||
.position-abstain { background-color: #ffff00;}
|
||||
.position-recuse { background-color: #c0c0c0;}
|
||||
.position-norecord { background-color: #ffffff;}
|
||||
.position-block { background-color: #c00;}
|
||||
.position-yes { background-color: #0d0;}
|
||||
.position-noobj { background-color: #0d0;}
|
||||
.position-abstain { background-color: #ff0;}
|
||||
.position-recuse { background-color: #bbb;}
|
||||
.position-norecord { background-color: #fff;}
|
||||
|
||||
.ballot-sidebar { width: 160px; float: left; margin-top: 0.4em; margin-right: 1em; padding: 0.5em; background: #edf5ff; }
|
||||
.ballot-icon table { empty-cells: show; padding: 0; border-spacing: 0; border: 1px solid #666; border-collapse: collapse; table-layout: fixed; min-width: 35px; background: #fff; }
|
||||
.ballot-icon table td { border: 1px solid #666; height: 7px; width: 6px; padding: 0;}
|
||||
.ballot-icon table td.my { border: 3px solid #000;}
|
||||
|
||||
.ballot-sidebar { width: 160px; float: left; margin-top: 0.4em; padding: 5px; background: #edf5ff; }
|
||||
.ballot-sidebar .action { margin-bottom: 1em; }
|
||||
.ballot-sidebar .position-group { margin-bottom: 1em; }
|
||||
.ballot-sidebar .position-group .heading { font-weight: bold; }
|
||||
|
@ -189,15 +199,14 @@ form table .help {
|
|||
.ballot-sidebar .position-group .was { padding-left: 10px; font-size:85%; }
|
||||
.ballot-sidebar .position-group:last-child { margin-bottom: 0; }
|
||||
|
||||
.ballot-content { margin-left: 180px; }
|
||||
.ballot-content { margin-left: 180px; } /* this positions the content to the right of the sidebar */
|
||||
.ballot-content .other-ballots { margin: 1em 0 2em 0; }
|
||||
.ballot-content .other-ballots a { display: inline-block; margin-right: 0.5em; }
|
||||
|
||||
#ballot_dialog_body { background-color: #fff; }
|
||||
#ballot_dialog_body .ballot-sidebar { margin-top: 0; }
|
||||
|
||||
.ballot-content h2.ad-ballot-comment { background: #2647A0; color: #fff; padding: 2px 4px; font-size: 108%; margin-top: 0;}
|
||||
|
||||
.ballot-popup > .content { width: 860px; height: 500px; overflow: auto; background: #fff; border: 1px solid #ccc; }
|
||||
.ballot-popup .ballot-sidebar { margin-top: 0; }
|
||||
|
||||
ul.messages { border: solid black 1px; margin: 0.4em 0; padding: 1em; }
|
||||
li.debug { margin: 0.5em; background-color: #ccf; }
|
||||
li.info { margin: 0.5em; background-color: #ff8; }
|
||||
|
@ -205,12 +214,17 @@ li.success { margin: 0.5em; background-color: #4f4; }
|
|||
li.warning { margin: 0.5em; background-color: #fc8; color: black;}
|
||||
li.error { margin: 0.5em; background-color: #f44; }
|
||||
|
||||
.group-documents .search-results { margin-top: 1.5em; }
|
||||
|
||||
table.milestones td.due { vertical-align: top; width: 80px; }
|
||||
table.milestones .doc { display: block; padding-left: 1em; }
|
||||
|
||||
.stream-state .milestone { display: inline-block; font-size: smaller; background-color: #d5dde6; padding: 0 0.2em; margin-left: 0.3em; }
|
||||
|
||||
.button, .button:hover:disabled {
|
||||
#modal-box { background: #f0f0f0; border-radius: 2px; padding: 10px; box-shadow: 0 0 4px rgba(0, 0, 0, 0.8); }
|
||||
|
||||
#modal-box .actions { padding-top: 1em; text-align: right; }
|
||||
|
||||
.button {
|
||||
display: inline-block; padding: 4px 12px; margin-right: 0.3em;
|
||||
color: #222; font-weight: normal; text-align: center; text-decoration: none; outline: none; cursor: pointer;
|
||||
background: #eee; background: linear-gradient(#fff, #e0e0e0); background: -webkit-linear-gradient(#fff, #e0e0e0); background: -moz-linear-gradient(#fff, #e0e0e0);
|
||||
|
@ -219,4 +233,4 @@ table.milestones .doc { display: block; padding-left: 1em; }
|
|||
}
|
||||
.button:hover { color: #111; background: #ddd; background: linear-gradient(#eee, #ccc); background: -webkit-linear-gradient(#eee, #ccc); background: -moz-linear-gradient(#eee, #ccc); }
|
||||
.button:active { color: #000; background: #ccc; }
|
||||
.button:disabled, .button:hover:disabled { color: #999; cursor: default; }
|
||||
.button:disabled, .button:hover:disabled { color: #999; cursor: default; background: #eee; background: linear-gradient(#fff, #e0e0e0); background: -webkit-linear-gradient(#fff, #e0e0e0); background: -moz-linear-gradient(#fff, #e0e0e0); }
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<Description>Use datatracker.ietf.org to search for Internet-Drafts and RFCs</Description>
|
||||
<Tags>Requests For Comments</Tags>
|
||||
<Url type="text/html"
|
||||
template="http://datatracker.ietf.org/doc/search/?name={searchTerms}&activeDrafts=on&rfcs=on&lucky=on"/>
|
||||
template="http://datatracker.ietf.org/doc/search/?name={searchTerms}&activedrafts=on&rfcs=on"/>
|
||||
<LongName>datatracker.ietf.org RFC and Internet-Draft Search</LongName>
|
||||
<Image height="16" width="16" type="image/vnd.microsoft.icon">http://datatracker.ietf.org/images/ietf-icon-blue.bmp</Image>
|
||||
<Developer>Tony Hansen</Developer>
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
$(function () {
|
||||
// search form
|
||||
var form = jQuery("#search_form");
|
||||
|
||||
// we want to disable our submit button if we have no search text,
|
||||
// and we have no advanced options selected
|
||||
function toggleSubmit() {
|
||||
var nameSearch = $.trim($("#id_name").val());
|
||||
|
||||
var noAdvanced = true;
|
||||
function anyAdvancedActive() {
|
||||
var advanced = false;
|
||||
|
||||
var by = form.find("input[name=by]:checked");
|
||||
if (by.length > 0)
|
||||
by.closest(".search_field").find("input,select").not("input[name=by]").each(function () {
|
||||
if ($.trim(this.value))
|
||||
noAdvanced = false;
|
||||
advanced = true;
|
||||
});
|
||||
|
||||
form.find("input[type=submit]").get(0).disabled = !nameSearch && noAdvanced;
|
||||
return advanced;
|
||||
}
|
||||
|
||||
function toggleSubmit() {
|
||||
var nameSearch = $.trim($("#id_name").val());
|
||||
form.find("input[type=submit]").get(0).disabled = !nameSearch && !anyAdvancedActive();
|
||||
}
|
||||
|
||||
function togglePlusMinus(toggler, toggled) {
|
||||
|
@ -29,7 +31,7 @@ $(function () {
|
|||
}
|
||||
}
|
||||
|
||||
function updateBy() {
|
||||
function updateAdvanced() {
|
||||
form.find("input[name=by]:checked").closest(".search_field").find("input,select").not("input[name=by]").each(function () {
|
||||
this.disabled = false;
|
||||
});
|
||||
|
@ -41,25 +43,24 @@ $(function () {
|
|||
toggleSubmit();
|
||||
}
|
||||
|
||||
form.find(".search_field input[name=by]").closest("label").click(updateBy);
|
||||
if (form.length > 0) {
|
||||
form.find(".search_field input[name=by]").closest("label").click(updateAdvanced);
|
||||
|
||||
form.find(".search_field input,select")
|
||||
.change(toggleSubmit).click(toggleSubmit).keyup(toggleSubmit);
|
||||
form.find(".search_field input,select")
|
||||
.change(toggleSubmit).click(toggleSubmit).keyup(toggleSubmit);
|
||||
|
||||
form.find(".toggle_advanced").click(function () {
|
||||
var advanced = $(this).next();
|
||||
advanced.find('.search_field input[type="radio"]').attr("checked", false);
|
||||
togglePlusMinus($(this), advanced);
|
||||
updateBy();
|
||||
});
|
||||
form.find(".toggle_advanced").click(function () {
|
||||
var advanced = $(this).next();
|
||||
advanced.find('.search_field input[type="radio"]').attr("checked", false);
|
||||
togglePlusMinus($(this), advanced);
|
||||
updateAdvanced();
|
||||
});
|
||||
|
||||
updateBy();
|
||||
updateAdvanced();
|
||||
}
|
||||
|
||||
$("#search_results th").click(function (e) {
|
||||
window.location = $(this).find("a").attr("href");
|
||||
})
|
||||
|
||||
$('#search_results .addtolist a').click(function(e) {
|
||||
// search results
|
||||
$('.search-results .addtolist a').click(function(e) {
|
||||
e.preventDefault();
|
||||
var trigger = $(this);
|
||||
$.ajax({
|
||||
|
@ -74,4 +75,27 @@ $(function () {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("a.ballot-icon").click(function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
url: $(this).data("popup"),
|
||||
success: function (data) {
|
||||
showModalBox(data);
|
||||
},
|
||||
error: function () {
|
||||
showModalBox("<div>Error retrieving popup content</div>");
|
||||
}
|
||||
});
|
||||
}).each(function () {
|
||||
// bind right-click shortcut
|
||||
var editPositionUrl = $(this).data("edit");
|
||||
if (editPositionUrl) {
|
||||
$(this).bind("contextmenu", function (e) {
|
||||
e.preventDefault();
|
||||
window.location = editPositionUrl;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
jQuery(function () {
|
||||
jQuery("table.history .snippet .showAll").click(function () {
|
||||
jQuery("table.history .snippet .show-all").click(function () {
|
||||
jQuery(this).parents(".snippet").hide().siblings(".full").show();
|
||||
});
|
||||
});
|
||||
|
|
43
static/js/utils.js
Normal file
43
static/js/utils.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
function showModalBox(content, callback) {
|
||||
content = $(content);
|
||||
|
||||
// make sure previous one is gone
|
||||
$("#modal-overlay").remove();
|
||||
|
||||
// the url(data:...) part is backwards compatibility for non-rgba
|
||||
// supporting browsers (IE 8) - it's a 2 pixel black PNG with
|
||||
// opacity 50%
|
||||
var overlay = $('<div id="modal-overlay" style="position:fixed;z-index:100;top:0;left:0;height:100%;width:100%;background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAQAAABeK7cBAAAACXBIWXMAAAsTAAALEwEAmpwYAAAADUlEQVQIHWNgqGeoBwACAQD/+EjsGgAAAABJRU5ErkJggg==);background:rgba(0,0,0,0.5);"></div>');
|
||||
var box = $('<div id="modal-box" style="position:absolute;left:50%;top:50%"></div>');
|
||||
|
||||
box.append(content);
|
||||
overlay.append(box);
|
||||
|
||||
box.click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
overlay.click(closeModalBox);
|
||||
box.find(".button.close").click(function (e) {
|
||||
e.preventDefault();
|
||||
closeModalBox();
|
||||
});
|
||||
overlay.keydown(function (e) {
|
||||
if (e.which == 27)
|
||||
closeModalBox();
|
||||
});
|
||||
|
||||
$("body").append(overlay);
|
||||
|
||||
var w = content.outerWidth() || 400;
|
||||
var h = content.outerHeight() || 300;
|
||||
box.css({ "margin-left": -parseInt(w/2), "margin-top": -parseInt(h/2) });
|
||||
|
||||
content.focus();
|
||||
|
||||
if (callback)
|
||||
callback();
|
||||
}
|
||||
|
||||
function closeModalBox() {
|
||||
$("#modal-overlay").remove();
|
||||
}
|
Loading…
Reference in a new issue