class JobOfferPage(StandardPage): parent_page_types = ["JobOfferIndexPage"] subpage_types = ["core.StandardPage"] valid_through = models.DateTimeField( "Bewerbungsfrist", blank=True, null=True, validators=[ MinValueValidator(timezone.now, message="Sollte in der Zukunft liegen") ], ) job_title = models.CharField("Job-Titel", max_length=255) job_location = models.CharField( "Job-Ort", max_length=255, blank=True, default="Hannover" ) hiring_organization_name = models.CharField( "Arbeitgeber", max_length=255, default="JANUN e.V." ) hiring_organization_url = models.URLField( "Website des Arbeitgebers", blank=True, default="https://www.janun.de/" ) EMPLOYMENT_TYPE_CHOICES = [ ("FULL_TIME", "Vollzeit"), ("PART_TIME", "Teilzeit"), ("CONTRACTOR", "Auftragnehmer"), ("TEMPORARY", "befristet"), ("INTERN", "Praktikum"), ("VOLUNTEER", "Freiwilligendienst"), ("PER_DIEM", "tageweise"), ("OTHER", "anderes"), ] employment_type = ChoiceArrayField( models.CharField(max_length=20, choices=EMPLOYMENT_TYPE_CHOICES), verbose_name="Art der Anstellung", blank=True, null=True, ) base_salary_amount = models.DecimalField( "Grundgehalt", blank=True, null=True, decimal_places=2, max_digits=10 ) BASE_SALARY_UNIT_CHOICES = [ ("HOUR", "pro Stunde"), ("DAY", "pro Tag"), ("WEEK", "pro Woche"), ("MONTH", "pro Monat"), ("YEAR", "pro Jahr"), ] base_salary_unit = models.CharField( "Zeitraum für Grundgehalt", max_length=10, default="MONTH", choices=BASE_SALARY_UNIT_CHOICES, ) auto_unpublish = models.BooleanField( "Automatisch depublizieren", help_text="Depubliziert die Seite automatisch nach der Bewerbungsfrist", default=True, ) def get_employment_type_display(self) -> [str]: result = [] for employment_type in self.employment_type: for choice in self.EMPLOYMENT_TYPE_CHOICES: if employment_type == choice[0]: result.append(choice[1]) return result @property def structured_data(self): return { "@type": "JobPosting", "title": self.job_title, "description": str(self.body), "datePosted": self.first_published_at, "validThrough": self.valid_through, "hiringOrganization": { "@type": "Organization", "name": self.hiring_organization_name, "sameAs": self.hiring_organization_url, }, "jobLocation": {"@type": "Place", "address": self.job_location}, "employmentType": self.employment_type, "baseSalary": { "@type": "MonetaryAmount", "currency": "EUR", "value": { "@type": "QuantitativeValue", "value": self.base_salary_amount, "unitText": self.base_salary_unit, }, }, } def save(self, *args, **kwargs): if self.valid_through and self.auto_unpublish: self.expire_at = self.valid_through super().save(*args, **kwargs) content_panels = [ FieldPanel("title"), FieldPanel("subtitle"), ImageChooserPanel("feed_image"), MultiFieldPanel( [ HelpPanel( "<p>Sorgt für eine bessere Platzierung als Jobanzeige bei Google und co.</p>" ), FieldPanel("job_title"), FieldPanel("job_location"), FieldPanel("hiring_organization_name"), FieldPanel("hiring_organization_url"), FieldPanel("valid_through"), FieldPanel("auto_unpublish"), FieldPanel("employment_type", widget=forms.CheckboxSelectMultiple), FieldPanel("base_salary_amount"), FieldPanel("base_salary_unit"), ], heading="Infos", ), StreamFieldPanel("body"), ] class Meta: verbose_name = "Stellenausschreibung" verbose_name_plural = "Stellenausschreibungen"
class JobListingPage(CFGOVPage): description = RichTextField('Summary') open_date = models.DateField('Open date') close_date = models.DateField('Close date') salary_min = models.DecimalField( 'Minimum salary', max_digits=11, decimal_places=2 ) salary_max = models.DecimalField( 'Maximum salary', max_digits=11, decimal_places=2 ) division = models.ForeignKey( JobCategory, on_delete=models.PROTECT, null=True ) job_length = models.ForeignKey( JobLength, on_delete=models.PROTECT, null=True, verbose_name="Position length", blank=True ) service_type = models.ForeignKey( ServiceType, on_delete=models.PROTECT, null=True, blank=True ) offices = ParentalManyToManyField( Office, related_name='job_listings', blank=True ) allow_remote = models.BooleanField( default=False, verbose_name="Office location can also be remote" ) regions = ParentalManyToManyField( Region, related_name='job_listings', blank=True ) responsibilities = RichTextField( 'Responsibilities', null=True, blank=True ) travel_required = models.BooleanField( blank=False, default=False, help_text=( 'Optional: Check to add a "Travel required" section to the ' 'job description. Section content defaults to "Yes".' ) ) travel_details = RichTextField( null=True, blank=True, help_text='Optional: Add content for "Travel required" section.' ) additional_section_title = models.CharField( max_length=255, null=True, blank=True, help_text='Optional: Add title for an additional section ' 'that will display at end of job description.' ) additional_section_content = RichTextField( null=True, blank=True, help_text='Optional: Add content for an additional section ' 'that will display at end of job description.' ) content_panels = CFGOVPage.content_panels + [ MultiFieldPanel([ FieldPanel('division'), InlinePanel('grades', label='Grades'), FieldRowPanel([ FieldPanel('open_date', classname='col6'), FieldPanel('close_date', classname='col6'), ]), FieldRowPanel([ FieldPanel('salary_min', classname='col6'), FieldPanel('salary_max', classname='col6'), ]), FieldRowPanel([ FieldPanel('service_type', classname='col6'), FieldPanel('job_length', classname='col6'), ]), ], heading='Details'), MultiFieldPanel([ HelpPanel(LOCATION_HELP_TEXT), FieldRowPanel([ FieldPanel('offices', widget=forms.CheckboxSelectMultiple), FieldPanel('allow_remote'), ]), FieldPanel('regions', widget=forms.CheckboxSelectMultiple), ], heading='Location'), MultiFieldPanel([ FieldPanel('description'), FieldPanel('responsibilities'), FieldPanel('travel_required'), FieldPanel('travel_details'), FieldPanel('additional_section_title'), FieldPanel('additional_section_content'), ], heading='Description'), InlinePanel( 'usajobs_application_links', label='USAJobs application links' ), InlinePanel( 'email_application_links', label='Email application links' ), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) base_form_class = JobListingPageForm objects = JobListingPageManager() def get_context(self, request, *args, **kwargs): context = super(JobListingPage, self).get_context(request) try: context['about_us'] = ReusableText.objects.get( title='About us (For consumers)' ) except ReusableText.DoesNotExist: pass context.update({ 'offices': [ { 'name': office.name, 'state_id': office.state_id, } for office in self.offices.all() ], 'regions': [ { 'name': region.name, 'states': [ state.abbreviation for state in region.states.all() ], 'major_cities': list( region.major_cities.values('name', 'state_id') ), } for region in self.regions.all() ], 'grades': list(map(str, self.grades.all())), }) return context @property def page_js(self): return super(JobListingPage, self).page_js + ['read-more.js']
class WimmelbildPage(BasePage): base_form_class = WimmelbildPageForm subtitle = models.CharField("Untertitel", max_length=255, blank=True) feed_image = models.ForeignKey( Image, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", verbose_name="Hauptbild", help_text="Wird in Übersichten verwendet.", ) before = StreamField( StandardStreamBlock(required=False), blank=True, null=True, verbose_name="Vor dem Wimmelbild", ) after = StreamField( StandardStreamBlock(required=False), blank=True, null=True, verbose_name="Nach dem Wimmelbild", ) tile_url = models.URLField( "Kachel-URL", help_text= "URL zu den Kacheln, aus denen das Bild besteht. Benutze {z}, {x}, {y} in der URL für die Koordinaten", blank=True, ) width = models.IntegerField("Breite", help_text="Breite des Wimmelbilds in Pixeln", blank=True, null=True) height = models.IntegerField("Höhe", help_text="Höhe des Wimmelbilds in Pixeln", blank=True, null=True) search_fields = BasePage.search_fields + [ index.SearchField("subtitle"), index.SearchField("before"), index.SearchField("after"), ] content_panels = [ FieldPanel("title"), FieldPanel("subtitle"), ImageChooserPanel("feed_image"), StreamFieldPanel("before"), HelpPanel("Hier kommt das Wimmelbild"), StreamFieldPanel("after"), ] wimmelbild_panels = [ MultiFieldPanel( [ HelpPanel( "Das Wimmelbild muss in Kacheln aufgeteilt werden (z.B. mit gdal2tiles) und diese dann Hochgeladen werden." ), FieldPanel("tile_url"), FieldPanel("width"), FieldPanel("height"), ], heading="Allgemeines", ), # HelpPanel(template="wimmelbilder/map_edit.html", heading="Übersicht über Info-Punkte"), # TODO InlinePanel("groups", heading="Gruppen von Info-Punkten"), InlinePanel("points", heading="Info-Punkte"), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading="Text-Inhalt"), ObjectList(wimmelbild_panels, heading="Wimmelbild"), ObjectList(BasePage.promote_panels, heading="Veröffentlichung"), ObjectList(BasePage.settings_panels, heading="Einstellungen", classname="settings"), ]) @property def json_dict(self): groups = [g.json_dict for g in self.groups.all()] jd = { "tileUrl": self.tile_url, "width": self.width, "height": self.height, "groups": groups, } return jd def clean(self): super().clean() if self.tile_url: if not self.width: raise ValidationError( {"width": "Erforderlich, wenn Kacheln angegeben"}) if not self.height: raise ValidationError( {"height": "Erforderlich, wenn Kacheln angegeben"}) class Meta: verbose_name = "Wimmelbild-Seite" verbose_name_plural = "Wimmelbild-Seiten"
class InternationalInvestmentSectorPagePanels: content_panels = [ FieldPanel('title'), MultiFieldPanel(heading='Heading', classname='collapsible', children=[ FieldPanel('heading'), ImageChooserPanel('hero_image'), MediaChooserPanel('hero_video'), FieldPanel('standfirst'), FieldPanel('featured_description') ]), MultiFieldPanel(heading='Intro', classname='collapsible', children=[ FieldPanel('intro_text'), ImageChooserPanel('intro_image'), ]), MultiFieldPanel(heading='Contact details', classname='collapsible', children=[ FieldPanel('contact_name'), ImageChooserPanel('contact_avatar'), FieldPanel('contact_job_title'), FieldPanel('contact_link'), FieldPanel('contact_link_button_preamble'), FieldPanel('contact_link_button_label'), ]), MultiFieldPanel( heading='Related opportunities', classname='collapsible', children=[ FieldPanel('related_opportunities_header'), HelpPanel( 'See the dedicated tab for selecting the opportunities themselves' ), ]), StreamFieldPanel('downpage_content'), MultiFieldPanel(heading='Early opportunities', classname='collapsible', children=[ FieldPanel('early_opportunities_header'), StreamFieldPanel('early_opportunities'), ]), SearchEngineOptimisationPanel() ] settings_panels = [ FieldPanel('slug'), FieldPanel('tags'), ] related_entities_panels = [ FieldRowPanel( heading='Related Opportunities', children=[ StreamFieldPanel('manually_selected_related_opportunities'), ]), ] edit_handler = make_translated_interface( content_panels=content_panels, other_panels=related_entities_panels, # These are shown as separate tabs settings_panels=settings_panels)
class InternationalSectorPage(BasePage): service_name_value = cms.GREAT_INTERNATIONAL parent_page_types = ['great_international.InternationalTopicLandingPage'] subpage_types = [] tags = ParentalManyToManyField(Tag, blank=True) heading = models.CharField(max_length=255) sub_heading = models.CharField(max_length=255) hero_image = models.ForeignKey( 'wagtailimages.Image', null=True, on_delete=models.SET_NULL, related_name='+' ) heading_teaser = models.TextField(blank=True) section_one_body = MarkdownField( null=True, verbose_name='Bullets markdown' ) section_one_image = models.ForeignKey( 'wagtailimages.Image', null=True, on_delete=models.SET_NULL, related_name='+', verbose_name='Bullets image' ) section_one_image_caption = models.CharField( max_length=255, blank=True, verbose_name='Bullets image caption') section_one_image_caption_company = models.CharField( max_length=255, blank=True, verbose_name='Bullets image caption — company name') statistic_1_number = models.CharField(max_length=255) statistic_1_heading = models.CharField(max_length=255) statistic_1_smallprint = models.CharField(max_length=255, blank=True) statistic_2_number = models.CharField(max_length=255) statistic_2_heading = models.CharField(max_length=255) statistic_2_smallprint = models.CharField(max_length=255, blank=True) statistic_3_number = models.CharField(max_length=255, blank=True) statistic_3_heading = models.CharField(max_length=255, blank=True) statistic_3_smallprint = models.CharField(max_length=255, blank=True) statistic_4_number = models.CharField(max_length=255, blank=True) statistic_4_heading = models.CharField(max_length=255, blank=True) statistic_4_smallprint = models.CharField(max_length=255, blank=True) statistic_5_number = models.CharField(max_length=255, blank=True) statistic_5_heading = models.CharField(max_length=255, blank=True) statistic_5_smallprint = models.CharField(max_length=255, blank=True) statistic_6_number = models.CharField(max_length=255, blank=True) statistic_6_heading = models.CharField(max_length=255, blank=True) statistic_6_smallprint = models.CharField(max_length=255, blank=True) section_two_heading = models.CharField( max_length=255, verbose_name='Highlights heading' ) section_two_teaser = models.TextField( verbose_name='Highlights teaser' ) section_two_subsection_one_icon = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name='Highlight 1 icon' ) section_two_subsection_one_heading = models.CharField( max_length=255, verbose_name='Highlight 1 heading' ) section_two_subsection_one_body = models.TextField( verbose_name='Highlight 1 body' ) section_two_subsection_two_icon = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name='Highlight 2 icon' ) section_two_subsection_two_heading = models.CharField( max_length=255, verbose_name='Highlight 2 heading' ) section_two_subsection_two_body = models.TextField( verbose_name='Highlight 2 body' ) section_two_subsection_three_icon = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name='Highlight 3 icon' ) section_two_subsection_three_heading = models.CharField( max_length=255, verbose_name='Highlight 3 heading' ) section_two_subsection_three_body = models.TextField( verbose_name='Highlight 3 body' ) case_study_title = models.CharField(max_length=255, blank=True) case_study_description = models.CharField(max_length=255, blank=True) case_study_cta_text = models.TextField(blank=True) case_study_cta_page = models.ForeignKey( 'wagtailcore.Page', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) case_study_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) section_three_heading = models.CharField( max_length=255, blank=True, verbose_name='Fact sheets heading' ) section_three_teaser = models.TextField( blank=True, verbose_name='Fact sheets teaser' ) section_three_subsection_one_heading = models.CharField( max_length=255, blank=True, verbose_name='Fact sheet 1 heading' ) section_three_subsection_one_teaser = models.TextField( blank=True, verbose_name='Fact sheet 1 teaser' ) section_three_subsection_one_body = MarkdownField( blank=True, null=True, verbose_name='Fact sheet 1 body' ) section_three_subsection_two_heading = models.CharField( max_length=255, blank=True, verbose_name='Fact sheet 2 heading' ) section_three_subsection_two_teaser = models.TextField( blank=True, verbose_name='Fact sheet 2 teaser' ) section_three_subsection_two_body = MarkdownField( blank=True, null=True, verbose_name='Fact sheet 2 body' ) related_page_one = models.ForeignKey( 'wagtailcore.Page', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) related_page_two = models.ForeignKey( 'wagtailcore.Page', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) related_page_three = models.ForeignKey( 'wagtailcore.Page', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) content_panels = [ MultiFieldPanel( heading='Heading', children=[ FieldPanel('heading'), FieldPanel('sub_heading'), ImageChooserPanel('hero_image'), FieldPanel('heading_teaser') ] ), MultiFieldPanel( heading='Bullets', children=[ HelpPanel( 'For accessibility reasons, use only "## [Your text here]"' ' for headings in this markdown field'), FieldRowPanel( [ FieldPanel('section_one_body'), MultiFieldPanel( [ ImageChooserPanel('section_one_image'), FieldPanel('section_one_image_caption'), FieldPanel('section_one_image_caption_company') ] ) ] ) ] ), MultiFieldPanel( heading='Statistics', children=[ FieldRowPanel( [ MultiFieldPanel( [ FieldPanel('statistic_1_number'), FieldPanel('statistic_1_heading'), FieldPanel('statistic_1_smallprint') ] ), MultiFieldPanel( [ FieldPanel('statistic_2_number'), FieldPanel('statistic_2_heading'), FieldPanel('statistic_2_smallprint') ] ), MultiFieldPanel( [ FieldPanel('statistic_3_number'), FieldPanel('statistic_3_heading'), FieldPanel('statistic_3_smallprint') ] ), MultiFieldPanel( [ FieldPanel('statistic_4_number'), FieldPanel('statistic_4_heading'), FieldPanel('statistic_4_smallprint') ] ), MultiFieldPanel( [ FieldPanel('statistic_5_number'), FieldPanel('statistic_5_heading'), FieldPanel('statistic_5_smallprint') ] ), MultiFieldPanel( [ FieldPanel('statistic_6_number'), FieldPanel('statistic_6_heading'), FieldPanel('statistic_6_smallprint') ] ), ] ) ] ), MultiFieldPanel( heading='Highlights', children=[ FieldPanel('section_two_heading'), FieldPanel('section_two_teaser'), FieldRowPanel( [ MultiFieldPanel( [ ImageChooserPanel( 'section_two_subsection_one_icon'), FieldPanel( 'section_two_subsection_one_heading'), FieldPanel( 'section_two_subsection_one_body') ] ), MultiFieldPanel( [ ImageChooserPanel( 'section_two_subsection_two_icon'), FieldPanel( 'section_two_subsection_two_heading'), FieldPanel( 'section_two_subsection_two_body') ] ), MultiFieldPanel( [ ImageChooserPanel( 'section_two_subsection_three_icon'), FieldPanel( 'section_two_subsection_three_heading'), FieldPanel( 'section_two_subsection_three_body') ] ) ] ) ] ), MultiFieldPanel( heading='Case Study', classname='collapsible', children=[ FieldPanel('case_study_title'), FieldPanel('case_study_description'), FieldPanel('case_study_cta_text'), PageChooserPanel( 'case_study_cta_page', [ 'great_international.InternationalArticlePage', 'great_international.InternationalCampaignPage', ]), ImageChooserPanel('case_study_image') ] ), MultiFieldPanel( heading='Fact Sheets', classname='collapsible collapsed', children=[ FieldPanel('section_three_heading'), FieldPanel('section_three_teaser'), FieldRowPanel( [ MultiFieldPanel( [ FieldPanel( 'section_three_subsection_one_heading'), FieldPanel( 'section_three_subsection_one_teaser'), HelpPanel( 'For accessibility reasons, use only ' '"#### [Your text here]" for subheadings ' 'in this markdown field'), FieldPanel( 'section_three_subsection_one_body') ] ), MultiFieldPanel( [ FieldPanel( 'section_three_subsection_two_heading'), FieldPanel( 'section_three_subsection_two_teaser'), HelpPanel( 'For accessibility reasons, use only ' '"#### [Your text here]" for subheadings ' 'in this markdown field'), FieldPanel( 'section_three_subsection_two_body') ] ) ] ) ] ), MultiFieldPanel( heading='Related articles', children=[ FieldRowPanel([ PageChooserPanel( 'related_page_one', [ 'great_international.InternationalArticlePage', 'great_international.InternationalCampaignPage', ]), PageChooserPanel( 'related_page_two', [ 'great_international.InternationalArticlePage', 'great_international.InternationalCampaignPage', ]), PageChooserPanel( 'related_page_three', [ 'great_international.InternationalArticlePage', 'great_international.InternationalCampaignPage', ]), ]) ] ), SearchEngineOptimisationPanel() ] settings_panels = [ FieldPanel('title_en_gb'), FieldPanel('slug'), FieldPanel('tags', widget=CheckboxSelectMultiple) ]
class ServicePage(JanisPage): # TODO: FKs # department = models.ForeignKey( # 'base.DepartmentPage', # on_delete=models.PROTECT, # verbose_name='Select a Department', # blank=True, # null=True, # ) steps = StreamField( [ ('basic_step', RichTextBlock(features=WYSIWYG_SERVICE_STEP, label='Basic Step')), ('step_with_options_accordian', StructBlock([ ('options_description', TextBlock('Describe the set of options')), ('options', ListBlock( StructBlock([ ('option_name', TextBlock( label= 'Option name. (When clicked, this name will expand the content for this option' )), ('option_description', RichTextBlock( features=WYSIWYG_SERVICE_STEP, label='Option Content', )), ]), )), ], label="Step With Options")), ], verbose_name= 'Write out the steps a resident needs to take to use the service', # this gets called in the help panel help_text= 'A step may have a basic text step or an options accordian which reveals two or more options', blank=True) # TODO: custom blocks # dynamic_content = StreamField( # [ # ('map_block', custom_blocks.SnippetChooserBlockWithAPIGoodness('base.Map', icon='site')), # ('what_do_i_do_with_block', custom_blocks.WhatDoIDoWithBlock()), # ('collection_schedule_block', custom_blocks.CollectionScheduleBlock()), # ('recollect_block', custom_blocks.RecollectBlock()), # ], # verbose_name='Add any maps or apps that will help the resident use the service', # blank=True # ) additional_content = RichTextField( features=WYSIWYG_GENERAL, verbose_name='Write any additional content describing the service', help_text='Section header: What else do I need to know?', blank=True) # TODO: custom forms base_form_class = custom_forms.ServicePageForm short_description = models.TextField( max_length=SHORT_DESCRIPTION_LENGTH, blank=True, verbose_name='Write a description of this service') content_panels = [ FieldPanel('title'), FieldPanel('short_description'), # TODO: FKs # InlinePanel('topics', label='Topics'), # FieldPanel('department'), MultiFieldPanel([ HelpPanel(steps.help_text, classname="coa-helpPanel"), StreamFieldPanel('steps') ], heading=steps.verbose_name, classname='coa-multiField-nopadding'), # TODO: custom blocks # StreamFieldPanel('dynamic_content'), MultiFieldPanel([ HelpPanel(additional_content.help_text, classname="coa-helpPanel"), FieldPanel('additional_content') ], heading=additional_content.verbose_name, classname='coa-multiField-nopadding'), # TODO: FKs # InlinePanel('contacts', label='Contacts'), ]
def __iter__(self): # build submenu panels, including the FluidIterable for the widget submenu_panels = [ HelpPanel(_("Select the menu that this sub-menu will load")), SubMenuFieldPanel("submenu_id", MenuListQuerySet()()), FieldPanel("display_option"), FieldPanel("show_when"), FieldPanel("menu_display_order"), FieldPanel("show_divider_after_this_item"), ] # two custom panels here: # ReadOnlyPanel - displays field as a non-field text, optionally adds a hidden input field to # allow accessing that field in the clean() method # RichHelpPanel - like a django template, swap out {{vars}} for values (field or function returns) # also allows basic html (formatting, links etc) msg = _( 'Items in the menu will be arranged by <b>Menu Display Order</b> over the order in which they appear below.' ) style = "margin-top: -1.5em; margin-bottom: -1.5em;" panels = [ MultiFieldPanel( [ ReadOnlyPanel( "id", heading="Menu ID", add_hidden_input=True), FieldPanel("title"), ImageChooserPanel("icon"), ], heading=_("Menu Heading"), ), MultiFieldPanel( [ RichHelpPanel( msg, style=style, ), ], heading=_( "Menu Items - Add items to show in the menu below. "), ), MultiFieldPanel( [ InlinePanel("sub_menu_items", label=_("Sub-menu"), panels=submenu_panels) ], heading="Submenus", classname="collapsible collapsed", ), MultiFieldPanel( [ InlinePanel("link_menu_items", label=_("Link")), ], heading="Links", classname="collapsible collapsed", ), MultiFieldPanel( [ InlinePanel("autofill_menu_items", label=_("Autofill Link")), ], heading="Autofill Links", classname="collapsible collapsed", ), ] return panels.__iter__()
class BlogPost(Page): """Model for blog posts""" # Main blog post content and information. intro = models.CharField(max_length=150, blank=True, null=True) date = models.DateTimeField("Post date") text = RichTextField(blank=True) tags = ClusterTaggableManager(through=BlogPostTag, related_name='blog_post_tag', blank=True) # Show or hide the gallery. show = models.BooleanField(null=True) # HTML meta tags for the specific blog post. description = models.CharField(max_length=160, blank=True, null=True) keywords = ClusterTaggableManager(through=BlogPostKeyword, related_name='blog_post_keyword', blank=True) search_fields = Page.search_fields + [ index.SearchField('intro'), index.SearchField('text'), ] content_panels = Page.content_panels + [ MultiFieldPanel([ HelpPanel(template='help_panel/content_help.html'), FieldPanel('intro'), FieldPanel('date'), FieldPanel('tags'), FieldPanel('text'), ], heading="Content"), MultiFieldPanel([ HelpPanel(template='help_panel/gallery_help.html'), FieldPanel('show', widget=forms.CheckboxInput), InlinePanel('gallery_images', label="Gallery images"), ], heading="Gallery"), MultiFieldPanel([ HelpPanel(template='help_panel/metatag_help.html'), FieldPanel('keywords', classname="full"), FieldPanel('description', classname="full"), ], heading="HTML meta tags"), ] def intro_text(self): """Return intro text for the tiles""" if self.intro: return self.intro + "..." else: # If no intro, remove HTML and return the 150 first character # of the posts text as intro instead. return re.sub("<[^>]*>", "", self.text[:300])[:150] + "..." def featured_image(self): """Give posts a feature image.""" gallery_item = self.gallery_images.first() if gallery_item: return gallery_item.image else: return None def next_post(self): """Return the next blog post.""" posts = self.get_siblings().live().filter( blogpost__date__lte=timezone.now()).order_by('-blogpost__date') next = None for post in posts: if post.title == self.title: return next next = post return None def previous_post(self): """Return the previous blog post.""" posts = self.get_siblings().live().filter( blogpost__date__lte=timezone.now()).order_by('blogpost__date') previous = None for post in posts: if post.title == self.title: return previous previous = post return None
class AboutUkRegionPagePanels: content_panels = [ FieldPanel('title'), FieldPanel('breadcrumbs_label'), MultiFieldPanel( heading="Hero", children=[ FieldPanel('hero_title'), ImageChooserPanel('hero_image'), ], ), FieldPanel('featured_description'), MultiFieldPanel( heading="Region summary", classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Region Summary Section Content'), ImageChooserPanel('region_summary_section_image'), FieldPanel('region_summary_section_strapline'), FieldPanel('region_summary_section_intro'), FieldPanel('region_summary_section_content'), ], ), MultiFieldPanel(heading="Investment opportunities", classname='collapsible collapsed', children=[ FieldPanel('investment_opps_title'), FieldPanel('investment_opps_intro'), ]), MultiFieldPanel( heading="Economics Statistics", classname='collapsible', children=[ HelpPanel( 'Required: at least 4 statistics for the section to show'), FieldRowPanel([ MultiFieldPanel([ FieldPanel('economics_stat_1_heading'), FieldPanel('economics_stat_1_number'), FieldPanel('economics_stat_1_smallprint'), ]), MultiFieldPanel([ FieldPanel('economics_stat_2_heading'), FieldPanel('economics_stat_2_number'), FieldPanel('economics_stat_2_smallprint'), ]), MultiFieldPanel([ FieldPanel('economics_stat_3_heading'), FieldPanel('economics_stat_3_number'), FieldPanel('economics_stat_3_smallprint'), ]), ]), FieldRowPanel([ MultiFieldPanel([ FieldPanel('economics_stat_4_heading'), FieldPanel('economics_stat_4_number'), FieldPanel('economics_stat_4_smallprint'), ]), MultiFieldPanel([ FieldPanel('economics_stat_5_heading'), FieldPanel('economics_stat_5_number'), FieldPanel('economics_stat_5_smallprint'), ]), MultiFieldPanel([ FieldPanel('economics_stat_6_heading'), FieldPanel('economics_stat_6_number'), FieldPanel('economics_stat_6_smallprint'), ]), ]), ], ), MultiFieldPanel( heading="Location Statistics", classname='collapsible', children=[ HelpPanel( 'Required: at least 4 statistics for the section to show'), FieldRowPanel([ MultiFieldPanel([ FieldPanel('location_stat_1_heading'), FieldPanel('location_stat_1_number'), FieldPanel('location_stat_1_smallprint'), ]), MultiFieldPanel([ FieldPanel('location_stat_2_heading'), FieldPanel('location_stat_2_number'), FieldPanel('location_stat_2_smallprint'), ]), MultiFieldPanel([ FieldPanel('location_stat_3_heading'), FieldPanel('location_stat_3_number'), FieldPanel('location_stat_3_smallprint'), ]), ]), FieldRowPanel([ MultiFieldPanel([ FieldPanel('location_stat_4_heading'), FieldPanel('location_stat_4_number'), FieldPanel('location_stat_4_smallprint'), ]), MultiFieldPanel([ FieldPanel('location_stat_5_heading'), FieldPanel('location_stat_5_number'), FieldPanel('location_stat_5_smallprint'), ]), MultiFieldPanel([ FieldPanel('location_stat_6_heading'), FieldPanel('location_stat_6_number'), FieldPanel('location_stat_6_smallprint'), ]), ]), ], ), MultiFieldPanel( heading="Extra optional Property and Infrastructure section", classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Property and Infrastructure Section Title, ' 'Property and Infrastructure Section Content'), ImageChooserPanel('property_and_infrastructure_section_image'), FieldPanel('property_and_infrastructure_section_title'), FieldPanel('property_and_infrastructure_section_content'), ], ), MultiFieldPanel( heading="Accordions subsections", classname='collapsible collapsed', children=[ HelpPanel( 'Required: subsections title and at least one title and content for an accordion to show' ), FieldPanel('subsections_title'), FieldRowPanel([ MultiFieldPanel([ FieldPanel('sub_section_one_title'), ImageChooserPanel('sub_section_one_icon'), FieldPanel('sub_section_one_content') ]), MultiFieldPanel([ FieldPanel('sub_section_two_title'), ImageChooserPanel('sub_section_two_icon'), FieldPanel('sub_section_two_content') ]), MultiFieldPanel([ FieldPanel('sub_section_three_title'), ImageChooserPanel('sub_section_three_icon'), FieldPanel('sub_section_three_content') ]), ]), ]), MultiFieldPanel( heading="Case study", classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Case Study Image, Case Study Title'), ImageChooserPanel('case_study_image'), FieldPanel('case_study_title'), FieldPanel('case_study_text'), HelpPanel('Cta\'s require both text and a link to show ' 'on page. '), FieldPanel('case_study_cta_text'), FieldPanel('case_study_cta_link'), ], ), MultiFieldPanel( heading="Contact", classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Contact Title, Contact Text'), FieldPanel('contact_title'), FieldPanel('contact_text'), FieldPanel('contact_cta_text'), FieldPanel('contact_cta_link'), ], ), SearchEngineOptimisationPanel() ] settings_panels = [ FieldPanel('slug'), ] edit_handler = make_translated_interface(content_panels=content_panels, settings_panels=settings_panels)
class AboutUkWhyChooseTheUkPagePanels: content_panels = [ FieldPanel('title'), FieldPanel('breadcrumbs_label'), MultiFieldPanel( heading="Hero", children=[ FieldPanel('hero_title'), ImageChooserPanel('hero_image'), ], ), MultiFieldPanel( heading="Teaser", children=[ FieldPanel('teaser'), FieldPanel('primary_contact_cta_text'), FieldPanel('primary_contact_cta_link') ], ), MultiFieldPanel( heading="Section 1", classname='collapsible', children=[ HelpPanel('At least one field required for section to show'), FieldRowPanel([ FieldPanel('section_one_body'), MultiFieldPanel([ ImageChooserPanel('section_one_image'), FieldPanel('section_one_video', widget=AdminMediaChooser) ]) ]) ], ), MultiFieldPanel(heading='Statistics', classname='collapsible', children=[ FieldRowPanel([ MultiFieldPanel([ FieldPanel('statistic_1_heading'), FieldPanel('statistic_1_number'), FieldPanel('statistic_1_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_2_heading'), FieldPanel('statistic_2_number'), FieldPanel('statistic_2_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_3_heading'), FieldPanel('statistic_3_number'), FieldPanel('statistic_3_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_4_heading'), FieldPanel('statistic_4_number'), FieldPanel('statistic_4_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_5_heading'), FieldPanel('statistic_5_number'), FieldPanel('statistic_5_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_6_heading'), FieldPanel('statistic_6_number'), FieldPanel('statistic_6_smallprint') ]), ]) ]), MultiFieldPanel(heading="Articles section", classname='collapsible', children=[ InlinePanel('about_uk_articles_fields', label="About UK articles") ]), MultiFieldPanel( heading="EBook section", classname='collapsible', children=[ HelpPanel('Required fields for section to show: title, body'), FieldRowPanel([ ImageChooserPanel('ebook_section_image'), FieldPanel('ebook_section_image_alt_text') ]), MultiFieldPanel([ FieldPanel('ebook_section_title'), FieldPanel('ebook_section_body'), HelpPanel( 'CTAs require both text and a link to show on page.'), FieldPanel('ebook_section_cta_text'), FieldPanel('ebook_section_cta_link'), ]), ]), MultiFieldPanel( heading="Related pages", classname='collapsible', children=[ HelpPanel( 'Required for section to show: title and at least one related page' ), FieldPanel('how_dit_help_title'), FieldRowPanel([ MultiFieldPanel([ PageChooserPanel( 'related_page_one', 'great_international.AboutDitServicesPage'), ]), MultiFieldPanel([ PageChooserPanel( 'related_page_two', 'great_international.AboutDitServicesPage'), ]), MultiFieldPanel([ PageChooserPanel( 'related_page_three', 'great_international.AboutDitServicesPage'), ]), ]), ], ), MultiFieldPanel( heading="Contact Section", classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Title, Summary'), FieldPanel('contact_us_section_title'), FieldPanel('contact_us_section_summary'), HelpPanel('CTAs require both text and a link to show ' 'on page. '), FieldPanel('contact_us_section_cta_text'), FieldPanel('contact_us_section_cta_link'), ], ), SearchEngineOptimisationPanel() ] settings_panels = [ FieldPanel('slug'), ] edit_handler = make_translated_interface(content_panels=content_panels, settings_panels=settings_panels)
class AboutUkLandingPagePanels: image_panels = [ ImageChooserPanel('hero_image'), ImageChooserPanel('why_choose_uk_image'), MultiFieldPanel(heading="How we help images", children=[ ImageChooserPanel('how_we_help_one_icon'), ImageChooserPanel('how_we_help_two_icon'), ImageChooserPanel('how_we_help_three_icon'), ImageChooserPanel('how_we_help_four_icon'), ImageChooserPanel('how_we_help_five_icon'), ImageChooserPanel('how_we_help_six_icon'), ]), ImageChooserPanel('ebook_section_image'), ] content_panels = [ FieldPanel('title'), FieldPanel('breadcrumbs_label'), MultiFieldPanel( heading="Hero", children=[ FieldPanel('hero_title'), ], ), FieldPanel('intro'), MultiFieldPanel(heading="Why choose the UK section", classname="collapsible", children=[ FieldPanel('why_choose_uk_title'), FieldPanel('why_choose_uk_content'), FieldPanel('why_choose_uk_cta_text'), FieldPanel('why_choose_uk_cta_link'), ]), MultiFieldPanel(heading="Key Industries section", classname="collapsible", children=[ FieldPanel('industries_section_title'), FieldPanel('industries_section_intro'), FieldPanel('industries_section_cta_text'), FieldPanel('industries_section_cta_link') ]), MultiFieldPanel( heading="UK's regions section", classname="collapsible", children=[ FieldPanel('regions_section_title'), FieldPanel('regions_section_intro'), FieldRowPanel([ MultiFieldPanel([ PageChooserPanel( 'scotland', ['great_international.AboutUkRegionPage']), FieldPanel('scotland_text') ]), MultiFieldPanel([ PageChooserPanel( 'northern_ireland', ['great_international.AboutUkRegionPage']), FieldPanel('northern_ireland_text') ]), MultiFieldPanel([ PageChooserPanel( 'north_england', ['great_international.AboutUkRegionPage']), FieldPanel('north_england_text') ]), ]), FieldRowPanel([ MultiFieldPanel([ PageChooserPanel( 'wales', ['great_international.AboutUkRegionPage']), FieldPanel('wales_text') ]), MultiFieldPanel([ PageChooserPanel( 'midlands', ['great_international.AboutUkRegionPage']), FieldPanel('midlands_text') ]), MultiFieldPanel([ PageChooserPanel( 'south_england', ['great_international.AboutUkRegionPage']), FieldPanel('south_england_text') ]), ]), FieldPanel('regions_section_cta_text'), FieldPanel('regions_section_cta_link'), ]), MultiFieldPanel(heading="How we help section", classname="collapsible", children=[ FieldPanel('how_we_help_title'), FieldPanel('how_we_help_intro'), FieldRowPanel([ MultiFieldPanel([ FieldPanel('how_we_help_one_title'), FieldPanel('how_we_help_one_text') ]), MultiFieldPanel([ FieldPanel('how_we_help_two_title'), FieldPanel('how_we_help_two_text') ]), MultiFieldPanel([ FieldPanel('how_we_help_three_title'), FieldPanel('how_we_help_three_text') ]), ]), FieldRowPanel([ MultiFieldPanel([ FieldPanel('how_we_help_four_title'), FieldPanel('how_we_help_four_text') ]), MultiFieldPanel([ FieldPanel('how_we_help_five_title'), FieldPanel('how_we_help_five_text') ]), MultiFieldPanel([ FieldPanel('how_we_help_six_title'), FieldPanel('how_we_help_six_text') ]), ]), FieldPanel('how_we_help_cta_text'), FieldPanel('how_we_help_cta_link') ]), MultiFieldPanel( heading="EBook section", classname='collapsible', children=[ HelpPanel('Required fields for section to show: title, body'), FieldRowPanel([FieldPanel('ebook_section_image_alt_text')]), MultiFieldPanel([ FieldPanel('ebook_section_title'), FieldPanel('ebook_section_body'), HelpPanel('CTAs require both text and a link to show ' 'on page. '), FieldPanel('ebook_section_cta_text'), DocumentChooserPanel('ebook_section_cta_link'), ]), ]), MultiFieldPanel(heading="Contact us section", classname="collapsible", children=[ FieldPanel('contact_title'), FieldPanel('contact_text'), FieldPanel('contact_cta_text'), FieldPanel('contact_cta_link'), ]), SearchEngineOptimisationPanel() ] settings_panels = [ FieldPanel('slug'), ] edit_handler = make_translated_interface(content_panels=content_panels, settings_panels=settings_panels, other_panels=[ ObjectList(image_panels, heading='Images'), ])
class AboutDitServicesPagePanels: content_panels = [ FieldPanel('title'), FieldPanel('breadcrumbs_label'), MultiFieldPanel( heading="Hero", children=[ FieldPanel('hero_title'), ], ), MultiFieldPanel( heading="Teaser", children=[ FieldPanel('teaser'), ], ), MultiFieldPanel( heading="EBook section", classname='collapsible', children=[ FieldRowPanel([FieldPanel('ebook_section_image_alt_text')]), MultiFieldPanel([ FieldPanel('ebook_section_body'), HelpPanel( 'CTAs require both text and a link to show on page. '), FieldPanel('ebook_section_cta_text'), FieldPanel('ebook_section_cta_link'), ]), ]), FieldPanel('featured_description'), MultiFieldPanel(heading="Services section", classname='collapsible', children=[ InlinePanel('about_dit_services_fields', label="About DIT services") ]), MultiFieldPanel( heading="Case study", classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Case Study Image, Case Study Title'), FieldPanel('case_study_title'), FieldPanel('case_study_text'), HelpPanel('CTAs require both text and a link to show ' 'on page. '), FieldPanel('case_study_cta_text'), FieldPanel('case_study_cta_link'), ], ), MultiFieldPanel( heading="Contact Section", classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Title, Summary'), FieldPanel('contact_us_section_title'), FieldPanel('contact_us_section_summary'), HelpPanel('CTAs require both text and a link to show ' 'on page. '), FieldPanel('contact_us_section_cta_text'), FieldPanel('contact_us_section_cta_link'), ], ), SearchEngineOptimisationPanel() ] image_panels = [ ImageChooserPanel('hero_image'), ImageChooserPanel('ebook_section_image'), ImageChooserPanel('case_study_image'), ] settings_panels = [ FieldPanel('slug'), ] edit_handler = make_translated_interface(content_panels=content_panels, settings_panels=settings_panels, other_panels=[ ObjectList(image_panels, heading='Images'), ])
class BaseInternationalSectorPagePanels: content_panels = [ FieldPanel('title'), MultiFieldPanel(heading='Heading', children=[ FieldPanel('heading'), FieldPanel('sub_heading'), ImageChooserPanel('hero_image'), FieldPanel('heading_teaser'), FieldPanel('featured_description') ]), MultiFieldPanel( heading='Unique selling points', children=[ HelpPanel( 'Use H2 (##) markdown for the three subheadings.' ' Required fields for section to show: 3 Unique Selling ' 'Points Markdown'), FieldRowPanel([ FieldPanel('section_one_body'), MultiFieldPanel([ ImageChooserPanel('section_one_image'), FieldPanel('section_one_image_caption'), FieldPanel('section_one_image_caption_company') ]) ]) ]), MultiFieldPanel(heading='Statistics', children=[ FieldRowPanel([ MultiFieldPanel([ FieldPanel('statistic_1_number'), FieldPanel('statistic_1_heading'), FieldPanel('statistic_1_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_2_number'), FieldPanel('statistic_2_heading'), FieldPanel('statistic_2_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_3_number'), FieldPanel('statistic_3_heading'), FieldPanel('statistic_3_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_4_number'), FieldPanel('statistic_4_heading'), FieldPanel('statistic_4_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_5_number'), FieldPanel('statistic_5_heading'), FieldPanel('statistic_5_smallprint') ]), MultiFieldPanel([ FieldPanel('statistic_6_number'), FieldPanel('statistic_6_heading'), FieldPanel('statistic_6_smallprint') ]), ]) ]), MultiFieldPanel( heading='Spotlight', children=[ FieldPanel('section_two_heading'), FieldPanel('section_two_teaser'), HelpPanel( 'Each icon needs a heading for it to show on the page.'), FieldRowPanel([ MultiFieldPanel([ ImageChooserPanel('section_two_subsection_one_icon'), FieldPanel('section_two_subsection_one_heading'), FieldPanel('section_two_subsection_one_body') ]), MultiFieldPanel([ ImageChooserPanel('section_two_subsection_two_icon'), FieldPanel('section_two_subsection_two_heading'), FieldPanel('section_two_subsection_two_body') ]), MultiFieldPanel([ ImageChooserPanel('section_two_subsection_three_icon'), FieldPanel('section_two_subsection_three_heading'), FieldPanel('section_two_subsection_three_body') ]) ]) ]), MultiFieldPanel( heading='Case Study', classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Case Study Image, Case Study Title'), FieldPanel('case_study_title'), FieldPanel('case_study_description'), FieldPanel('case_study_cta_text'), HelpPanel('Cta\'s require both text and a link to show ' 'on page. '), PageChooserPanel('case_study_cta_page', [ 'great_international.InternationalArticlePage', 'great_international.InternationalCampaignPage', ]), ImageChooserPanel('case_study_image') ]), MultiFieldPanel( heading='Fact Sheets', classname='collapsible collapsed', children=[ FieldPanel('section_three_heading'), FieldPanel('section_three_teaser'), FieldRowPanel([ MultiFieldPanel([ FieldPanel('section_three_subsection_one_heading'), FieldPanel('section_three_subsection_one_teaser'), HelpPanel('For accessibility reasons, use only ' '"#### [Your text here]" for subheadings ' 'in this markdown field'), FieldPanel('section_three_subsection_one_body') ]), MultiFieldPanel([ FieldPanel('section_three_subsection_two_heading'), FieldPanel('section_three_subsection_two_teaser'), HelpPanel('For accessibility reasons, use only ' '"#### [Your text here]" for subheadings ' 'in this markdown field'), FieldPanel('section_three_subsection_two_body') ]) ]) ]), MultiFieldPanel( heading='Related articles', children=[ FieldRowPanel([ PageChooserPanel('related_page_one', [ 'great_international.InternationalArticlePage', 'great_international.InternationalCampaignPage', ]), PageChooserPanel('related_page_two', [ 'great_international.InternationalArticlePage', 'great_international.InternationalCampaignPage', ]), PageChooserPanel('related_page_three', [ 'great_international.InternationalArticlePage', 'great_international.InternationalCampaignPage', ]), ]) ]), MultiFieldPanel( heading='Project Opportunities', classname='collapsible ', children=[ FieldPanel('project_opportunities_title'), HelpPanel('Up to 3 random opportunities that are related ' 'to this sector will appear here.'), FieldPanel('related_opportunities_cta_text'), FieldPanel('related_opportunities_cta_link') ]), SearchEngineOptimisationPanel() ] settings_panels = [ FieldPanel('slug'), FieldPanel('tags', widget=CheckboxSelectMultiple) ] edit_handler = make_translated_interface(content_panels=content_panels, settings_panels=settings_panels)
class LocationPage(JanisBasePage): """ all the relevant details for a specifc location (place!?) decide if we want to set null or cascade """ janis_url_page_type = 'location' alternate_name = models.CharField(max_length=DEFAULT_MAX_LENGTH, blank=True, verbose_name="Location alternate name", help_text="Use this field if the building has a second name, or is inside a larger facility") physical_street = models.CharField(max_length=DEFAULT_MAX_LENGTH, blank=True, verbose_name="Street") physical_unit = models.CharField(max_length=DEFAULT_MAX_LENGTH, blank=True, verbose_name="Floor/Suite #") physical_city = models.CharField(max_length=DEFAULT_MAX_LENGTH, default='Austin', blank=True, verbose_name="City") physical_state = models.CharField(max_length=DEFAULT_MAX_LENGTH, default='TX', blank=True, verbose_name="State") physical_country = models.CharField(max_length=DEFAULT_MAX_LENGTH, default='USA', blank=True) physical_zip = models.CharField(max_length=DEFAULT_MAX_LENGTH, blank=True, verbose_name="ZIP") physical_location_photo = models.ForeignKey( TranslatedImage, null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name="Choose a banner image", help_text="Use this to show an exterior of the location." ) phone_description = models.CharField( max_length=DEFAULT_MAX_LENGTH, blank=True, verbose_name="Phone description") phone_number = PhoneNumberField(blank=True, verbose_name="Phone(only if location has a dedicated number)") email = models.EmailField(blank=True, verbose_name="Email address") mailing_street = models.CharField(max_length=DEFAULT_MAX_LENGTH, blank=True, verbose_name="Street or PO box") mailing_city = models.CharField(max_length=DEFAULT_MAX_LENGTH, default='Austin', blank=True, verbose_name="City") mailing_state = models.CharField(max_length=DEFAULT_MAX_LENGTH, default='TX', blank=True, verbose_name="State") mailing_country = models.CharField(max_length=DEFAULT_MAX_LENGTH, default='USA', blank=True) mailing_zip = models.CharField(max_length=DEFAULT_MAX_LENGTH, blank=True, verbose_name="ZIP") nearest_bus_1 = models.IntegerField(null=True, blank=True) nearest_bus_2 = models.IntegerField(null=True, blank=True) nearest_bus_3 = models.IntegerField(null=True, blank=True) parent_page_types = ['base.HomePage'] content_panels = [ FieldPanel('title_en', widget=countMe), FieldPanel('title_es', widget=countMe), FieldPanel('title_ar'), FieldPanel('title_vi'), MultiFieldPanel(children=[ FieldPanel('physical_street'), FieldPanel('physical_unit', classname='col2'), FieldPanel('physical_city', classname='col5'), FieldPanel('physical_state', classname='col4'), FieldPanel('physical_zip', classname='col2'), ], heading='Location physical address'), MultiFieldPanel( [ HelpPanel(physical_location_photo.help_text, classname="coa-helpPanel"), ImageChooserPanel('physical_location_photo'), ], heading=physical_location_photo.verbose_name, classname='coa-multiField-nopadding' ), MultiFieldPanel(children=[ FieldPanel('mailing_street'), FieldPanel('mailing_city', classname='col5'), FieldPanel('mailing_state', classname='col4'), FieldPanel('mailing_zip', classname='col2'), ], heading='Location mailing address (if applicable)', classname="collapsible" ), MultiFieldPanel( [ HelpPanel(alternate_name.help_text, classname="coa-helpPanel"), FieldPanel('alternate_name'), ], heading=alternate_name.verbose_name, classname='coa-multiField-nopadding' ), FieldRowPanel( children=[ FieldPanel('phone_number', classname='col6', widget=PhoneNumberInternationalFallbackWidget), FieldPanel('phone_description', classname='col6'), FieldPanel('email', classname='col6'), ], heading="Location contact info" ), FieldRowPanel( children=[ FieldPanel('nearest_bus_1'), FieldPanel('nearest_bus_2'), FieldPanel('nearest_bus_3'), ], heading="Location details" ), ]
class MapLocation(index.Indexed, ClusterableModel): title = models.CharField(max_length=255, help_text="The name as it appears on the map.") description = RichTextField(blank=True) node_id = models.CharField(blank=True, max_length=255) x = models.CharField(blank=True, max_length=255) y = models.CharField(blank=True, max_length=255) width = models.CharField(blank=True, max_length=255) height = models.CharField(blank=True, max_length=255) rotate = models.CharField( blank=True, max_length=10, help_text= "Rotates the icon/title on the map, in degrees (180, -45, 90, etc)") node_html = models.TextField(blank=True) node_css = models.TextField(blank=True) type = models.CharField(choices=[ ('continent', 'Continent'), ('hidden', 'Hidden'), ('ocean', 'Ocean'), ('none', 'Not on map'), ('standard', 'Standard'), ('text', 'Text'), ('turtle', 'Turtle'), ], null=True, blank=False, default='standard', max_length=255) def __str__(self): return self.title def _title(self): return format_html('<b style="min-width: 200px;">{}</b>', self.title) def _description(self): return format_html('<div style="max-width:500px;">{}</div>', format_html(self.description)) def _image(self): layer = MapLocationImage.objects.filter(location=self).first() if layer and layer.image: return format_html( '<img class="species-thumbnail" src="{}" />', layer.image.file.url, ) else: return None def _overlay(self): layers = MapLocationOverlay.objects.filter(location=self) if layers: html = '<div class="map-overlay-thumbnail">' for layer in layers: html += format_html( '<img style="max-width:300px; border: 1px solid #333;" src="{}" />', layer.image.file.url, ) html += '</div>' return format_html(html) else: return None panels = [ FieldPanel('title'), FieldPanel('type'), FieldPanel('description'), MultiFieldPanel([ FieldPanel('node_id'), FieldPanel('rotate'), FieldPanel('width'), FieldPanel('height'), FieldPanel('x'), FieldPanel('y'), ], heading="Positioning"), MultiFieldPanel([ FieldPanel('node_html', classname="code-editor"), HelpPanel( content= 'Paste HTML code here to overwrite settings. HTML can be generated <a target="_blank" href="https://www.inabrains.com/tooltip/image-hotspot-creator.html">here</a>.' ), FieldPanel('node_css', classname="code-editor"), HelpPanel(content='Inline styles for this node.'), ], heading="Code"), MultiFieldPanel([ InlinePanel('node_image'), HelpPanel( content='Replace the dot with an image. Can be multiple layers.' ), ], heading="Node Replacement Image"), MultiFieldPanel([ InlinePanel('overlay_image'), HelpPanel( content= 'Overlays for the entire map, activated on hover. Should match the resolution of the map image.' ), ], heading="Overlay Image"), ] def save(self): # If code exists, overwrite existing coords if self.node_html: # Extract attrs from div soup = BeautifulSoup(self.node_html + "</div>", 'html5lib') div = soup.div attrs = div.attrs self.node_id = attrs.get('id', self.node_id) # Extract styles rx = re.compile(r'(?:width|height|top|left):[^;]+;?') styles = rx.findall(self.node_html) # Assign found styles to fields for style in styles: if 'width' in style: self.width = style.replace(';', '').replace('width:', '').strip(' ') if 'height' in style: self.height = style.replace(';', '').replace('height:', '').strip(' ') if 'left' in style: self.x = style.replace(';', '').replace('left:', '').strip(' ') if 'top' in style: self.y = style.replace(';', '').replace('top:', '').strip(' ') self.node_html = '' super(MapLocation, self).save()
class CoderedPage(Page, metaclass=CoderedPageMeta): """ General use page with caching, templating, and SEO functionality. All pages should inherit from this. """ class Meta: verbose_name = _('CodeRed Page') # Do not allow this page type to be created in wagtail admin is_creatable = False # Templates # The page will render the following templates under certain conditions: # # template = '' # amp_template = '' # ajax_template = '' # search_template = '' ############### # Content fields ############### cover_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=_('Cover image'), ) ############### # Index fields ############### # Subclasses can override this to enabled index features by default. index_show_subpages_default = False # Subclasses can override this to query on a specific # page model, rather than the default wagtail Page. index_query_pagemodel = 'wagtailcore.Page' # Subclasses can override these fields to enable custom # ordering based on specific subpage fields. index_order_by_default = '-first_published_at' index_order_by_choices = ( ('-first_published_at', _('Date first published, newest to oldest')), ('first_published_at', _('Date first published, oldest to newest')), ('-last_published_at', _('Date updated, newest to oldest')), ('last_published_at', _('Date updated, oldest to newest')), ('title', _('Title, alphabetical')), ('-title', _('Title, reverse alphabetical')), ) index_show_subpages = models.BooleanField( default=index_show_subpages_default, verbose_name=_('Show list of child pages')) index_order_by = models.CharField( max_length=255, choices=index_order_by_choices, default=index_order_by_default, verbose_name=_('Order child pages by'), ) index_num_per_page = models.PositiveIntegerField( default=10, verbose_name=_('Number per page'), ) tags = ClusterTaggableManager( through=CoderedTag, verbose_name='Tags', blank=True, help_text=_('Used to categorize your pages.')) ############### # Layout fields ############### custom_template = models.CharField(blank=True, max_length=255, choices=None, verbose_name=_('Template')) ############### # SEO fields ############### og_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=_('Open Graph preview image'), help_text= _('The image shown when linking to this page on social media. If blank, defaults to article cover image, or logo in Settings > Layout > Logo' )) struct_org_type = models.CharField( default='', blank=True, max_length=255, choices=schema.SCHEMA_ORG_CHOICES, verbose_name=_('Organization type'), help_text=_('If blank, no structured data will be used on this page.')) struct_org_name = models.CharField( default='', blank=True, max_length=255, verbose_name=_('Organization name'), help_text=_('Leave blank to use the site name in Settings > Sites')) struct_org_logo = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=_('Organization logo'), help_text=_('Leave blank to use the logo in Settings > Layout > Logo')) struct_org_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=_('Photo of Organization'), help_text= _('A photo of the facility. This photo will be cropped to 1:1, 4:3, and 16:9 aspect ratios automatically.' )) struct_org_phone = models.CharField( blank=True, max_length=255, verbose_name=_('Telephone number'), help_text= _('Include country code for best results. For example: +1-216-555-8000' )) struct_org_address_street = models.CharField( blank=True, max_length=255, verbose_name=_('Street address'), help_text=_( 'House number and street. For example, 55 Public Square Suite 1710' )) struct_org_address_locality = models.CharField( blank=True, max_length=255, verbose_name=_('City'), help_text=_('City or locality. For example, Cleveland')) struct_org_address_region = models.CharField( blank=True, max_length=255, verbose_name=_('State'), help_text=_('State, province, county, or region. For example, OH')) struct_org_address_postal = models.CharField( blank=True, max_length=255, verbose_name=_('Postal code'), help_text=_('Zip or postal code. For example, 44113')) struct_org_address_country = models.CharField( blank=True, max_length=255, verbose_name=_('Country'), help_text= _('For example, USA. Two-letter ISO 3166-1 alpha-2 country code is also acceptible https://en.wikipedia.org/wiki/ISO_3166-1' )) struct_org_geo_lat = models.DecimalField( blank=True, null=True, max_digits=10, decimal_places=8, verbose_name=_('Geographic latitude')) struct_org_geo_lng = models.DecimalField( blank=True, null=True, max_digits=10, decimal_places=8, verbose_name=_('Geographic longitude')) struct_org_hours = StreamField([ ('hours', OpenHoursBlock()), ], blank=True, verbose_name=_('Hours of operation')) struct_org_actions = StreamField( [('actions', StructuredDataActionBlock())], blank=True, verbose_name=_('Actions')) struct_org_extra_json = models.TextField( blank=True, verbose_name=_('Additional Organization markup'), help_text= _('Additional JSON-LD inserted into the Organization dictionary. Must be properties of https://schema.org/Organization or the selected organization type.' )) ############### # Settings ############### content_walls = StreamField([('content_wall', ContentWallBlock())], blank=True, verbose_name=_('Content Walls')) ############### # Search ############### search_fields = [ index.SearchField('title', partial_match=True, boost=3), index.SearchField('seo_title', partial_match=True, boost=3), index.SearchField('search_description', boost=2), index.FilterField('title'), index.FilterField('id'), index.FilterField('live'), index.FilterField('owner'), index.FilterField('content_type'), index.FilterField('path'), index.FilterField('depth'), index.FilterField('locked'), index.FilterField('first_published_at'), index.FilterField('last_published_at'), index.FilterField('latest_revision_created_at'), index.FilterField('index_show_subpages'), index.FilterField('index_order_by'), index.FilterField('custom_template'), ] ############### # Panels ############### content_panels = (Page.content_panels + [ ImageChooserPanel('cover_image'), ]) body_content_panels = [] bottom_content_panels = [ FieldPanel('tags'), ] layout_panels = [ MultiFieldPanel([FieldPanel('custom_template')], heading=_('Visual Design')), MultiFieldPanel([ FieldPanel('index_show_subpages'), FieldPanel('index_num_per_page'), FieldPanel('index_order_by'), ], heading=_('Show Child Pages')) ] promote_panels = [ MultiFieldPanel([ FieldPanel('slug'), FieldPanel('seo_title'), FieldPanel('search_description'), ImageChooserPanel('og_image'), ], _('Page Meta Data')), MultiFieldPanel([ HelpPanel( heading=_('About Organization Structured Data'), content= _("""The fields below help define brand, contact, and storefront information to search engines. This information should be filled out on the site’s root page (Home Page). If your organization has multiple locations, then also fill this info out on each location page using that particular location’s info."""), ), FieldPanel('struct_org_type'), FieldPanel('struct_org_name'), ImageChooserPanel('struct_org_logo'), ImageChooserPanel('struct_org_image'), FieldPanel('struct_org_phone'), FieldPanel('struct_org_address_street'), FieldPanel('struct_org_address_locality'), FieldPanel('struct_org_address_region'), FieldPanel('struct_org_address_postal'), FieldPanel('struct_org_address_country'), FieldPanel('struct_org_geo_lat'), FieldPanel('struct_org_geo_lng'), StreamFieldPanel('struct_org_hours'), StreamFieldPanel('struct_org_actions'), FieldPanel('struct_org_extra_json'), ], _('Structured Data - Organization')), ] settings_panels = (Page.settings_panels + [ StreamFieldPanel('content_walls'), ]) def __init__(self, *args, **kwargs): """ Inject custom choices and defalts into the form fields to enable customization by subclasses. """ super().__init__(*args, **kwargs) klassname = self.__class__.__name__.lower() template_choices = cr_settings['FRONTEND_TEMPLATES_PAGES'].get('*', ()) + \ cr_settings['FRONTEND_TEMPLATES_PAGES'].get(klassname, ()) self._meta.get_field( 'index_order_by').choices = self.index_order_by_choices self._meta.get_field('custom_template').choices = template_choices if not self.id: self.index_order_by = self.index_order_by_default self.index_show_subpages = self.index_show_subpages_default @classmethod def get_edit_handler(cls): """ Override to "lazy load" the panels overriden by subclasses. """ return TabbedInterface([ ObjectList(cls.content_panels + cls.body_content_panels + cls.bottom_content_panels, heading='Content'), ObjectList(cls.layout_panels, heading='Layout'), ObjectList(cls.promote_panels, heading='SEO', classname="seo"), ObjectList(cls.settings_panels, heading='Settings', classname="settings"), ]).bind_to_model(cls) def get_struct_org_name(self): """ Gets org name for sturctured data using a fallback. """ if self.struct_org_name: return self.struct_org_name return self.get_site().site_name def get_struct_org_logo(self): """ Gets logo for structured data using a fallback. """ if self.struct_org_logo: return self.struct_org_logo else: layout_settings = LayoutSettings.for_site(self.get_site()) if layout_settings.logo: return layout_settings.logo return None def get_template(self, request, *args, **kwargs): """ Override parent to serve different templates based on querystring. """ if 'amp' in request.GET and hasattr(self, 'amp_template'): seo_settings = SeoSettings.for_site(request.site) if seo_settings.amp_pages: if request.is_ajax(): return self.ajax_template or self.amp_template return self.amp_template if self.custom_template: return self.custom_template return super(CoderedPage, self).get_template(request, args, kwargs) def get_index_children(self): """ Override to return query of subpages as defined by `index_` variables. """ if self.index_query_pagemodel: querymodel = resolve_model_string(self.index_query_pagemodel, self._meta.app_label) return querymodel.objects.child_of(self).order_by( self.index_order_by) return super().get_children().live() def get_content_walls(self, check_child_setting=True): current_content_walls = [] if check_child_setting: for wall in self.content_walls: content_wall = wall.value if wall.value['show_content_wall_on_children']: current_content_walls.append(wall.value) else: current_content_walls = self.content_walls try: return list(current_content_walls) + self.get_parent( ).specific.get_content_walls() except AttributeError: return list(current_content_walls) def get_context(self, request, *args, **kwargs): """ Add child pages and paginated child pages to context. """ context = super().get_context(request) if self.index_show_subpages: all_children = self.get_index_children() paginator = Paginator(all_children, self.index_num_per_page) page = request.GET.get('p', 1) try: paged_children = paginator.page(page) except: paged_children = paginator.page(1) context['index_paginated'] = paged_children context['index_children'] = all_children context['content_walls'] = self.get_content_walls( check_child_setting=False) return context
class ArticlePage(Page): tags = ClusterTaggableManager(through=ArticlePageTag, blank=True) author_image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') author_name = models.CharField(max_length=10, validators=[MinLengthValidator(2)]) article_datetime = models.DateTimeField() article_cover = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') article_cover_app = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') description = models.TextField(blank=True) liked_count = models.IntegerField(default=0) body = StreamField([ ('Paragraph', blocks.RichTextBlock()), ('RawHTML', blocks.RawHTMLBlock()), ('DocumentChooser', DocumentChooserBlock()), ]) content_panels = Page.content_panels + [ HelpPanel('建议文章标题不超过30个字'), FieldPanel('tags'), HelpPanel('建议标签数量最多2个,标签字数1~5个'), FieldPanel('description'), ImageChooserPanel('author_image'), FieldPanel('author_name'), FieldPanel('article_datetime'), ImageChooserPanel('article_cover'), ImageChooserPanel('article_cover_app'), StreamFieldPanel('body'), ] api_fields = [ APIField('tags'), APIField('author_image'), APIField('author_name'), APIField('article_datetime', serializer=DateTimeField(format="%Y-%m-%d %H:%M")), APIField('article_cover'), APIField('article_cover_app'), APIField('description'), APIField('liked_count'), # This will nest the relevant BlogPageAuthor objects in the API response ] parent_page_types = ['ArticleListPage'] subpage_types = [] def get_datetime_format(self): return self.article_datetime.strftime("%Y-%m-%d %H:%I") @property def first_tag(self): if self.tags: return self.tags.first() else: return None
class InvestmentOpportunityPagePanels: content_panels = [ MultiFieldPanel( heading='Opportunity Page title, intro and summary', classname='collapsible', children=[ FieldPanel('title'), FieldPanel('breadcrumbs_label'), ImageChooserPanel('hero_image'), MediaChooserPanel('hero_video'), FieldPanel('strapline'), FieldPanel('introduction'), ImageChooserPanel('intro_image'), FieldPanel('opportunity_summary'), ], ), MultiFieldPanel( heading="Key facts", classname='collapsible', children=[ FieldRowPanel([ FieldPanel('promoter'), FieldPanel('location'), MultiFieldPanel(heading='Scale', children=[ FieldPanel('scale'), FieldPanel('scale_value'), ]), ]), FieldRowPanel([ FieldPanel('planning_status'), FieldPanel('investment_type'), FieldPanel('time_to_investment_decision'), ]), HelpPanel( 'In addition to these, please also set a location in the Location tab' ), ], ), MultiFieldPanel( heading='Opportunity Contact', classname='collapsible', children=[ FieldPanel('contact_name'), ImageChooserPanel('contact_avatar'), FieldPanel('contact_job_title'), FieldPanel('contact_link'), ], ), MultiFieldPanel( heading='The Opportunity', classname='collapsible', children=[ StreamFieldPanel('main_content'), FieldPanel('important_links'), ], ), SearchEngineOptimisationPanel(), ] related_entities_panels = [ FieldRowPanel(heading='Location and Relevant Regions', classname='collapsible', children=[ StreamFieldPanel('regions_with_locations'), ]), FieldRowPanel( heading="Sectors and Sub-sectors", classname='collapsible collapsed', children=[ InlinePanel('related_sectors', label="Related Sectors"), InlinePanel('related_sub_sectors', label="Related Sub-sectors") ], ), ] settings_panels = [ FieldPanel('slug'), FieldPanel('priority_weighting'), ] edit_handler = make_translated_interface( content_panels=content_panels, other_panels=related_entities_panels, # These are shown as separate tabs settings_panels=settings_panels, )
class SeoDefault(BaseSetting): """ Social media accounts. """ class Meta: verbose_name = _("SEO Default Each Page") ############### # SEO fields ############### search_description = models.CharField(blank=True, max_length=1023) struct_org_type = models.CharField( default="", blank=True, max_length=255, choices=schema.SCHEMA_ORG_CHOICES, verbose_name=_("Organization type"), help_text=_("If blank, no structured data will be used on this page."), ) struct_org_name = models.CharField( default="", blank=True, max_length=255, verbose_name=_("Organization name"), help_text=_("Leave blank to use the site name in Settings > Sites"), ) struct_org_logo = models.ForeignKey( get_image_model_string(), null=True, blank=True, on_delete=models.SET_NULL, related_name="+", verbose_name=_("Organization logo"), help_text=_("Leave blank to use the logo in Settings > Layout > Logo"), ) struct_org_image = models.ForeignKey( get_image_model_string(), null=True, blank=True, on_delete=models.SET_NULL, related_name="+", verbose_name=_("Photo of Organization"), help_text= _("A photo of the facility. This photo will be cropped to 1:1, 4:3, and 16:9 aspect ratios automatically." ), # noqa ) struct_org_phone = models.CharField( blank=True, max_length=255, verbose_name=_("Telephone number"), help_text= _("Include country code for best results. For example: +1-216-555-8000" ), ) struct_org_address_street = models.CharField( blank=True, max_length=255, verbose_name=_("Street address"), help_text=_( "House number and street. For example, 55 Public Square Suite 1710" ), ) struct_org_address_locality = models.CharField( blank=True, max_length=255, verbose_name=_("City"), help_text=_("City or locality. For example, Cleveland"), ) struct_org_address_region = models.CharField( blank=True, max_length=255, verbose_name=_("State"), help_text=_("State, province, county, or region. For example, OH"), ) struct_org_address_postal = models.CharField( blank=True, max_length=255, verbose_name=_("Postal code"), help_text=_("Zip or postal code. For example, 44113"), ) struct_org_address_country = models.CharField( blank=True, max_length=255, verbose_name=_("Country"), help_text= _("For example, USA. Two-letter ISO 3166-1 alpha-2 country code is also acceptible https://en.wikipedia.org/wiki/ISO_3166-1" ), # noqa ) struct_org_geo_lat = models.DecimalField( blank=True, null=True, max_digits=10, decimal_places=8, verbose_name=_("Geographic latitude"), ) struct_org_geo_lng = models.DecimalField( blank=True, null=True, max_digits=11, decimal_places=8, verbose_name=_("Geographic longitude"), ) struct_org_hours = StreamField([ ("hours", OpenHoursBlock()), ], blank=True, verbose_name=_("Hours of operation")) struct_org_actions = StreamField( [("actions", StructuredDataActionBlock())], blank=True, verbose_name=_("Actions"), ) struct_org_extra_json = models.TextField( blank=True, verbose_name=_("Additional Organization markup"), help_text= _("Additional JSON-LD inserted into the Organization dictionary. Must be properties of https://schema.org/Organization or the selected organization type." ), # noqa ) panels = [ MultiFieldPanel( [ FieldPanel("company_name"), FieldPanel("email"), FieldPanel("telephone_number"), FieldPanel("handphone_number_1"), FieldPanel("handphone_number_2"), FieldPanel("address"), FieldPanel("copyright_year"), ], _("Profile"), ) ] panels = [ MultiFieldPanel( [ FieldPanel("search_description"), ], _("Page Meta Data"), ), MultiFieldPanel( [ HelpPanel( heading=_("About Organization Structured Data"), content= _("""The fields below help define brand, contact, and storefront information to search engines. This information should be filled out on the site’s root page (Home Page). If your organization has multiple locations, then also fill this info out on each location page using that particular location’s info."""), ), FieldPanel("struct_org_type"), FieldPanel("struct_org_name"), ImageChooserPanel("struct_org_logo"), ImageChooserPanel("struct_org_image"), FieldPanel("struct_org_phone"), FieldPanel("struct_org_address_street"), FieldPanel("struct_org_address_locality"), FieldPanel("struct_org_address_region"), FieldPanel("struct_org_address_postal"), FieldPanel("struct_org_address_country"), FieldPanel("struct_org_geo_lat"), FieldPanel("struct_org_geo_lng"), StreamFieldPanel("struct_org_hours"), StreamFieldPanel("struct_org_actions"), FieldPanel("struct_org_extra_json"), ], _("Structured Data - Organization"), ), ]
class ShortCoursePage(ContactFieldsMixin, BasePage): template = "patterns/pages/shortcourses/short_course.html" parent_page_types = ["programmes.ProgrammeIndexPage"] hero_image = models.ForeignKey( "images.CustomImage", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) introduction = models.CharField(max_length=500, blank=True) introduction_image = models.ForeignKey( get_image_model_string(), null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) video_caption = models.CharField( blank=True, max_length=80, help_text="The text dipsplayed next to the video play button", ) video = models.URLField(blank=True) body = RichTextField(blank=True) about = StreamField( [("accordion_block", AccordionBlockWithTitle())], blank=True, verbose_name=_("About the course"), ) access_planit_course_id = models.IntegerField(blank=True, null=True) frequently_asked_questions = models.ForeignKey( "utils.ShortCourseDetailSnippet", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) terms_and_conditions = models.ForeignKey( "utils.ShortCourseDetailSnippet", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) course_details_text = RichTextField(blank=True) show_register_link = models.BooleanField( default=1, help_text="If selected, an automatic 'Register your interest' link will be \ visible in the key details section", ) course_details_text = RichTextField(blank=True) programme_type = models.ForeignKey( ProgrammeType, on_delete=models.SET_NULL, blank=False, null=True, related_name="+", ) location = RichTextField(blank=True, features=["link"]) introduction = models.CharField(max_length=500, blank=True) quote_carousel = StreamField( [("quote", QuoteBlock())], blank=True, verbose_name=_("Quote carousel") ) staff_title = models.CharField( max_length=50, blank=True, help_text="Heading to display above the short course team members, E.G Programme Team", ) gallery = StreamField( [("slide", GalleryBlock())], blank=True, verbose_name="Gallery" ) external_links = StreamField( [("link", LinkBlock())], blank=True, verbose_name="External Links" ) application_form_url = models.URLField( blank=True, help_text="Adding an application form URL will override the Access Planit booking modal", ) manual_registration_url = models.URLField( blank=True, help_text="Override the register interest link show in the modal", ) access_planit_and_course_data_panels = [ MultiFieldPanel( [ FieldPanel("manual_registration_url"), HelpPanel( "Defining course details manually will override any Access Planit data configured for this page" ), InlinePanel("manual_bookings", label="Booking"), ], heading="Manual course configuration", ), MultiFieldPanel( [FieldPanel("application_form_url")], heading="Application URL" ), FieldPanel("access_planit_course_id"), MultiFieldPanel( [ FieldPanel("course_details_text"), SnippetChooserPanel("frequently_asked_questions"), SnippetChooserPanel("terms_and_conditions"), ], heading="course details", ), ] content_panels = BasePage.content_panels + [ MultiFieldPanel([ImageChooserPanel("hero_image")], heading=_("Hero"),), MultiFieldPanel( [ FieldPanel("introduction"), ImageChooserPanel("introduction_image"), FieldPanel("video"), FieldPanel("video_caption"), FieldPanel("body"), ], heading=_("Course Introduction"), ), StreamFieldPanel("about"), FieldPanel("programme_type"), StreamFieldPanel("quote_carousel"), MultiFieldPanel( [FieldPanel("staff_title"), InlinePanel("related_staff", label="Staff")], heading="Short course team", ), StreamFieldPanel("gallery"), MultiFieldPanel([*ContactFieldsMixin.panels], heading="Contact information"), MultiFieldPanel( [InlinePanel("related_programmes", label="Related programmes")], heading="Related Programmes", ), MultiFieldPanel( [ InlinePanel( "related_schools_and_research_pages", label=_("Related Schools and Research centre pages"), ) ], heading=_("Related Schools and Research Centre pages"), ), StreamFieldPanel("external_links"), ] key_details_panels = [ InlinePanel("fee_items", label="Fees"), FieldPanel("location"), FieldPanel("show_register_link"), InlinePanel("subjects", label=_("Subjects")), ] edit_handler = TabbedInterface( [ ObjectList(content_panels, heading="Content"), ObjectList(key_details_panels, heading="Key details"), ObjectList( access_planit_and_course_data_panels, heading="Course configuration" ), ObjectList(BasePage.promote_panels, heading="Promote"), ObjectList(BasePage.settings_panels, heading="Settings"), ] ) search_fields = BasePage.search_fields + [ index.SearchField("introduction", partial_match=True), index.AutocompleteField("introduction", partial_match=True), index.RelatedFields( "programme_type", [ index.SearchField("display_name", partial_match=True), index.AutocompleteField("display_name", partial_match=True), ], ), index.RelatedFields( "subjects", [ index.RelatedFields( "subject", [ index.SearchField("title", partial_match=True), index.AutocompleteField("title", partial_match=True), ], ) ], ), ] api_fields = [ # Fields for filtering and display, shared with programmes.ProgrammePage. APIField("subjects"), APIField("programme_type"), APIField("related_schools_and_research_pages"), APIField("summary", serializer=CharFieldSerializer(source="introduction")), APIField( name="hero_image_square", serializer=ImageRenditionField("fill-580x580", source="hero_image"), ), ] @property def get_manual_bookings(self): return self.manual_bookings.all() def get_access_planit_data(self): access_planit_course_data = AccessPlanitXML( course_id=self.access_planit_course_id ) return access_planit_course_data.get_data() def _format_booking_bar(self, register_interest_link=None, access_planit_data=None): """ Booking bar messaging with the next course data available Find the next course date marked as status='available' and advertise this date in the booking bar. If there are no courses available, add a default message.""" booking_bar = { "message": "Bookings not yet open", "action": "Register your interest for upcoming dates", } # If there are no dates the booking link should go to a form, not open # a modal, this link is also used as a generic interest link too though. booking_bar["link"] = register_interest_link # If manual_booking links are defined, format the booking bar and return # it before checking access planit if self.manual_bookings.first(): date = self.manual_bookings.first() booking_bar["message"] = "Next course starts" booking_bar["date"] = date.start_date if date.booking_link: booking_bar["action"] = ( f"Book from \xA3{date.cost}" if date.cost else "Book now" ) booking_bar["modal"] = "booking-details" booking_bar["cost"] = date.cost return booking_bar # If there is access planit data, format the booking bar if access_planit_data: for date in access_planit_data: if date["status"] == "Available": booking_bar["message"] = "Next course starts" booking_bar["date"] = date["start_date"] booking_bar["cost"] = date["cost"] if self.application_form_url: # URL has been provided to override AccessPlanit booking booking_bar["action"] = "Complete form to apply" booking_bar["link"] = self.application_form_url booking_bar["modal"] = None else: # Open AccessPlanit booking modal booking_bar["action"] = f"Book now from \xA3{date['cost']}" booking_bar["link"] = None booking_bar["modal"] = "booking-details" break return booking_bar # Check for a manual_registration_url if there is no data if self.manual_registration_url: booking_bar["link"] = self.manual_registration_url return booking_bar def clean(self): super().clean() errors = defaultdict(list) if ( self.show_register_link and not self.manual_registration_url and not self.access_planit_course_id ): errors["show_register_link"].append( "An access planit course ID or manual registration link is needed to show the register links" ) if self.access_planit_course_id: try: checker = AccessPlanitCourseChecker( course_id=self.access_planit_course_id ) if not checker.course_exists(): errors["access_planit_course_id"].append( "Could not find a course with this ID" ) except AccessPlanitException: errors["access_planit_course_id"].append( "Error checking this course ID in Access Planit. Please try again shortly." ) if errors: raise ValidationError(errors) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) access_planit_data = self.get_access_planit_data() context[ "register_interest_link" ] = ( register_interest_link ) = f"{settings.ACCESS_PLANIT_REGISTER_INTEREST_BASE}?course_id={self.access_planit_course_id}" context["booking_bar"] = self._format_booking_bar( register_interest_link, access_planit_data ) context["booking_bar"] = self._format_booking_bar( register_interest_link, access_planit_data ) context["access_planit_data"] = access_planit_data context["shortcourse_details_fees"] = self.fee_items.values_list( "text", flat=True ) context["related_sections"] = [ { "title": "More opportunities to study at the RCA", "related_items": [ rel.page.specific for rel in self.related_programmes.select_related("page") ], } ] context["related_staff"] = self.related_staff.select_related( "image" ).prefetch_related("page") return context
class HomePage(Page): """Model for the websites homepage""" # For the header on the homepage. header_header = models.CharField(max_length=100, blank=False) header_image = models.ForeignKey('wagtailimages.Image', blank=False, null=True, on_delete=models.SET_NULL, related_name='+') header_body = RichTextField(blank=False) # These will affect the whole site. See wagtailblog/context_processor.py. logo_image = models.ForeignKey('wagtailimages.Image', blank=False, null=True, on_delete=models.SET_NULL, related_name='+') favicon_file = models.ForeignKey('wagtaildocs.Document', blank=False, null=True, on_delete=models.SET_NULL, related_name='+') footer = RichTextField(blank=False) instagram = models.URLField(blank=False) # HTML meta tags for the homepage. keywords = ClusterTaggableManager(through=HomePageKeywords, blank=True) description = models.CharField(max_length=160, blank=True, null=True) # Instagram widget on the homepage. show_widget = models.BooleanField(null=True) instagram_widget = models.TextField(blank=True, null=True) content_panels = Page.content_panels + [ MultiFieldPanel([ HelpPanel(template='help_panel/branding_help.html'), ImageChooserPanel('logo_image'), DocumentChooserPanel('favicon_file'), ], heading="Branding"), MultiFieldPanel([ HelpPanel(template='help_panel/metatag_help.html'), FieldPanel('keywords'), FieldPanel('description'), ], heading="HTML meta tags"), MultiFieldPanel([ FieldPanel('header_header', classname='title'), FieldPanel('header_body'), ImageChooserPanel('header_image'), ], heading="Header"), MultiFieldPanel([ HelpPanel(template='help_panel/widget_help.html'), FieldPanel('show_widget', widget=forms.CheckboxInput), FieldPanel('instagram_widget'), ], heading="Instagram widget"), MultiFieldPanel([ HelpPanel(template='help_panel/footer_help.html'), FieldPanel('footer'), FieldPanel('instagram'), ], heading="Footer"), ] def latest_posts(self): """Get the six latest published posts""" posts = BlogPost.objects.live().filter( date__lte=timezone.now()).order_by('-date')[:6] return posts def get_context(self, request): """Context variables for the homepage template""" context = super().get_context(request) context['latest_posts'] = self.latest_posts context['show_widget'] = self.show_widget context['instagram_widget'] = self.instagram_widget context['homepage_header_image'] = self.header_image.file.url return context
class SchoolPage(ContactFieldsMixin, LegacyNewsAndEventsMixin, BasePage): template = "patterns/pages/schools/schools.html" introduction = RichTextField(blank=False, features=["link"]) introduction_image = models.ForeignKey( get_image_model_string(), null=True, blank=False, on_delete=models.SET_NULL, related_name="+", help_text= "This image appears after the intro copy. If a video is uploaded, this image is required", ) video_caption = models.CharField( blank=True, max_length=80, help_text=_("The text displayed next to the video play button"), ) video = models.URLField(blank=True) body = RichTextField() school_dean = models.ForeignKey( "people.StaffPage", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) # location location = RichTextField(blank=True, features=["link"]) next_open_day_date = models.DateField(blank=True, null=True) link_to_open_days = models.URLField(blank=True) # Get in touch get_in_touch = RichTextField(blank=True, features=["link"]) # Social Links social_links = StreamField(StreamBlock([("Link", LinkBlock())], max_num=5), blank=True) news_and_events_heading = models.CharField(blank=True, max_length=120) collaborators_heading = models.CharField(blank=True, max_length=120) collaborators = StreamField( StreamBlock([("Collaborator", LinkedImageBlock())], max_num=9), blank=True, help_text="You can add up to 9 collaborators. Minimum 200 x 200 pixels. \ Aim for logos that sit on either a white or transparent background.", ) about_external_links = StreamField( [("link", InternalExternalLinkBlock())], blank=True, verbose_name="External links", ) about_cta_block = StreamField( StreamBlock( [("call_to_action", CallToActionBlock(label=_("text promo")))], max_num=1), verbose_name="CTA", blank=True, ) research_projects_title = models.CharField(max_length=125, default="Our Research") research_projects_text = RichTextField(blank=True, features=["link"]) external_links_heading = models.CharField(max_length=125, blank=True) external_links = StreamField([("link", InternalExternalLinkBlock())], blank=True) research_cta_block = StreamField( StreamBlock( [("call_to_action", CallToActionBlock(label=_("text promo")))], max_num=1, ), blank=True, ) research_collaborators_heading = models.CharField(blank=True, max_length=120) research_collaborators = StreamField( StreamBlock([("Collaborator", LinkedImageBlock())], max_num=9), blank=True, help_text="You can add up to 9 collaborators. Minimum 200 x 200 pixels. \ Aim for logos that sit on either a white or transparent background.", ) related_programmes_title = models.CharField(blank=True, max_length=120) related_programmes_summary = models.CharField(blank=True, max_length=500) related_short_courses_title = models.CharField(blank=True, max_length=120) related_short_courses_summary = models.CharField(blank=True, max_length=500) programmes_links_heading = models.CharField(max_length=125, blank=True, verbose_name="Links heading") programmes_external_links = StreamField( [("link", InternalExternalLinkBlock())], blank=True, verbose_name="Links") programmes_cta_block = StreamField( StreamBlock( [("call_to_action", CallToActionBlock(label=_("text promo")))], max_num=1, verbose_name="Call to action", ), blank=True, ) # Staff staff_title = models.CharField(blank=True, max_length=120, verbose_name="Related staff title") staff_summary = models.CharField(blank=True, max_length=500, verbose_name="Related staff summary text") staff_external_links = StreamField([("link", InternalExternalLinkBlock())], blank=True, verbose_name="Links") staff_external_links_heading = models.CharField( max_length=125, blank=True, verbose_name="Related staff links heading") staff_cta_block = StreamField( StreamBlock( [("call_to_action", CallToActionBlock(label=_("text promo")))], max_num=1, verbose_name="Call to action", ), blank=True, ) staff_link = models.URLField(blank=True) staff_link_text = models.CharField(max_length=125, blank=True, help_text="E.g. 'See all staff'") search_fields = BasePage.search_fields + [ index.SearchField("introduction") ] api_fields = [APIField("introduction")] # Admin panel configuration content_panels = [ *BasePage.content_panels, InlinePanel( "hero_items", max_num=6, label="Hero Items", help_text="You can add up to 6 hero images", ), FieldPanel("introduction"), ImageChooserPanel("introduction_image"), MultiFieldPanel([FieldPanel("video"), FieldPanel("video_caption")], heading="Video"), FieldPanel("body"), ] key_details_panels = [ PageChooserPanel("school_dean"), MultiFieldPanel( [ FieldPanel("next_open_day_date"), FieldPanel("link_to_open_days") ], heading="Next open day", ), FieldPanel("location"), FieldPanel("get_in_touch"), StreamFieldPanel("social_links"), ] about_panel = [ InlinePanel("page_teasers", max_num=1, label="Page teasers"), MultiFieldPanel( [ FieldPanel("collaborators_heading"), StreamFieldPanel("collaborators") ], heading="Collaborators", ), InlinePanel("stats_block", label="Statistics", max_num=1), StreamFieldPanel("about_external_links"), StreamFieldPanel("about_cta_block"), ] news_and_events_panels = [ FieldPanel("news_and_events_heading"), InlinePanel("student_stories", label="Student Stories", max_num=1), FieldPanel("legacy_news_and_event_tags"), ] research_panels = [ MultiFieldPanel( [ FieldPanel("research_projects_title"), FieldPanel("research_projects_text"), HelpPanel( content="Projects related to this School are automatically \ listed, this can be overriden by defining projects manually" ), InlinePanel("manually_related_project_pages", max_num=5, label="Project"), ], heading="Research projects", ), MultiFieldPanel( [ InlinePanel( "student_research", label="Student research", max_num=1) ], heading="Student research", ), MultiFieldPanel( [ FieldPanel("research_collaborators_heading"), StreamFieldPanel("research_collaborators"), ], heading="Collaborators", ), MultiFieldPanel( [ FieldPanel("external_links_heading"), StreamFieldPanel("external_links") ], heading="Links", ), MultiFieldPanel([StreamFieldPanel("research_cta_block")], heading="Call To Action"), ] programmes_panels = [ FieldPanel("related_programmes_title"), FieldPanel("related_programmes_summary"), ] short_course_panels = [ FieldPanel("related_short_courses_title"), FieldPanel("related_short_courses_summary"), InlinePanel("related_short_courses", label="Short Course Pages"), MultiFieldPanel( [ FieldPanel("programmes_links_heading"), StreamFieldPanel("programmes_external_links"), ], heading="Links", ), MultiFieldPanel([StreamFieldPanel("programmes_cta_block")], heading="Call To Action"), ] staff_panels = [ FieldPanel("staff_title"), FieldPanel("staff_summary"), InlinePanel("related_staff", label="Related staff"), HelpPanel( content= "By default, related staff will be automatically listed. This \ can be overriden by adding staff pages here."), MultiFieldPanel( [FieldPanel("staff_link_text"), FieldPanel("staff_link")], heading="View more staff link", ), MultiFieldPanel( [ FieldPanel("staff_external_links_heading"), StreamFieldPanel("staff_external_links", heading="Links"), ], heading="Links", ), StreamFieldPanel("staff_cta_block", heading="Call to action"), ] contact_panels = [ MultiFieldPanel([*ContactFieldsMixin.panels], heading="Contact information"), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading="Introduction"), ObjectList(key_details_panels, heading="Key details"), ObjectList(about_panel, heading="About"), ObjectList(news_and_events_panels, heading="News and Events"), ObjectList(research_panels, heading="Our research"), ObjectList(programmes_panels, heading="Programmes"), ObjectList(short_course_panels, heading="Short Courses"), ObjectList(staff_panels, heading="Staff"), ObjectList(contact_panels, heading="Contact"), ObjectList(BasePage.promote_panels, heading="Promote"), ObjectList(BasePage.settings_panels, heading="Settings"), ]) def get_hero_image(self): # Select a random image from the set of hero items added hero_items = self.hero_items.all() if not hero_items: return selected_item = random.choice(hero_items) return { "image": selected_item.hero_image, } def clean(self): errors = defaultdict(list) super().clean() if self.staff_link and not self.staff_link_text: errors["staff_link_text"].append( _("Missing text value for the link")) if self.staff_link_text and not self.staff_link: errors["staff_link"].append(_("Missing url value for the link")) if errors: raise ValidationError(errors) def page_nav(self): # If these are updated, the id in the template's FE will need to be updated to match # TODO conditionally set/remove depending on fields return [ { "title": "Overview" }, { "title": "Research" }, { "title": "Study" }, { "title": "Staff" }, { "title": "Contact" }, ] def get_related_projects(self): """ Displays latest projects related to this school page. Returns: List of: filtered and formatted manually related ProjectPages or automatically fetch project pages from project > school relationship """ from rca.projects.models import ProjectPage manual_related_projects = [ i.page.id for i in self.manually_related_project_pages.select_related("page") ] auto_related_projects = ProjectPage.objects.filter( related_school_pages__page_id=self.id)[:6] if manual_related_projects: return format_projects_for_gallery( ProjectPage.objects.filter(id__in=manual_related_projects)) elif auto_related_projects: return format_projects_for_gallery(auto_related_projects) def get_student_research(self, student_research, request): if not student_research: return {} if student_research.link_page: link = student_research.link_page.get_url(request) else: link = student_research.link_url return { "title": student_research.title, "link_url": link, "link_text": student_research.link_text or student_research.link_page, "slides": related_list_block_slideshow(student_research.slides), } def get_student_stories(self, student_stories, request): if not student_stories: return {} return { "title": student_stories.title, "slides": related_list_block_slideshow(student_stories.slides), } def get_related_programmes(self): """ Get programme pages from the programme_page__school relationship. Returns: List -- of filtered and formatted Programme Pages. """ ProgrammePage = apps.get_model("programmes", "ProgrammePage") all_programmes = ProgrammePage.objects.live().public() return all_programmes.filter( related_schools_and_research_pages__page_id=self.id) def get_programme_index_link(self): ProgrammeIndexPage = apps.get_model("programmes", "ProgrammeIndexPage") programme_index = ProgrammeIndexPage.objects.live().first() if programme_index: return programme_index.get_url() def get_short_courses_index_link(self): """Returns a link to the programme index page filtered by the Short Course ProgrammeType """ ProgrammeType = apps.get_model("programmes", "ProgrammeType") short_course_type = ProgrammeType.objects.filter( display_name="Short course").first() if short_course_type: return ( f"{self.get_programme_index_link()}?category=programme_type&" f"value={short_course_type.id}-{slugify(short_course_type.display_name)}" ) def get_related_staff(self): """Method to return a related staff. The default behaviour should be to find related staff via the relationship from StaffPage > SchoolPage. This also needs to offer the option to manually add related staff to the school page, this helps solve issues of custom ordering that's needed with large (>25) staff items. """ from rca.people.models import StaffPage related_staff = self.related_staff.select_related("image") if related_staff: return related_staff # For any automatially related staff, adjust the list so we don't have # to make edits to the template shared by other page models. staff = [] for item in (StaffPage.objects.filter( related_schools__page=self).live().order_by("last_name")): staff.append({"page": item}) return staff def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) hero_image = self.get_hero_image() if hero_image: context["hero_image"] = hero_image["image"] context["page_teasers"] = format_page_teasers( self.page_teasers.first()) context["stats_block"] = self.stats_block.select_related( "background_image").first() context["featured_research"] = self.get_related_projects() context["student_research"] = self.get_student_research( self.student_research.first(), request) context["student_stories"] = self.get_student_stories( self.student_stories.first(), request) context["staff"] = self.get_related_staff() # Set the page tab titles for the jump menu context["related_programmes"] = [ { "related_items": [page.specific for page in self.get_related_programmes()], "link": { "url": self.get_programme_index_link, "title": "Browse all RCA programmes", }, }, ] context["related_short_courses"] = [{ "related_items": [ rel.page.specific for rel in self.related_short_courses.select_related("page") ], "link": { "url": self.get_short_courses_index_link(), "title": "Browse all RCA short courses", }, }] # Set the page tab titles for the jump menu context["tabs"] = self.page_nav() return context
class JobOfferIndexPage(BasePage): subpage_types = ["JobOfferPage"] max_count_per_parent = 1 heading = models.CharField("Überschrift", max_length=255, blank=True) highlight_in_heading = models.CharField( "Hervorhebungen in der Überschrift", help_text="Wiederhole Text aus der Überschrift der farblich hervorgehoben werden soll", blank=True, max_length=255, ) subtitle = models.CharField("Untertitel", max_length=255, blank=True) before_jobs = StreamField( StandardStreamBlock, blank=True, verbose_name="Intro-Text (wenn Jobs vorhanden)", help_text="Wird als Text vor der Liste der Stellenanzeigen angezeigt. Aber nur wenn es auch Stellenanzeigen gibt.", ) after_jobs = StreamField( StandardStreamBlock, blank=True, verbose_name="Outro-Text (wenn Jobs vorhanden)", help_text="Wird als Text nach der Liste der Stellenanzeigen angezeigt. Aber nur wenn es auch Stellenanzeigen gibt.", ) empty = StreamField( StandardStreamBlock(), blank=True, null=True, verbose_name="Wenn keine Jobs", help_text="Wird angezeigt, wenn es keine Stellenanzeigen gibt.", ) def get_context(self, request): context = super().get_context(request) context["jobs"] = JobOfferPage.objects.all().live() return context search_fields = BasePage.search_fields + [ index.SearchField("heading"), index.SearchField("subtitle"), index.SearchField("before_jobs"), index.SearchField("after_jobs"), ] content_panels = [ MultiFieldPanel( [ FieldPanel("title"), FieldPanel("heading"), FieldPanel("highlight_in_heading"), FieldPanel("subtitle"), ], "Kopf", ), StreamFieldPanel("before_jobs"), HelpPanel( template="jobs/admin_add_job_button.html", heading="Stellenauschreibung erstellen", ), StreamFieldPanel("after_jobs"), StreamFieldPanel("empty"), ] class Meta: verbose_name = "Auflistung von Stellenausschreibungen" verbose_name_plural = "Auflistungen von Stellenausschreibungen"
class InvestHomePage(ExclusivePageMixin, ServiceHomepageMixin, BaseInvestPage): slug_identity = slugs.INVEST_HOME_PAGE view_path = '' breadcrumbs_label = models.CharField(max_length=50) heading = models.CharField(max_length=255) sub_heading = models.CharField(max_length=255) hero_call_to_action_text = models.CharField(max_length=255, blank=True) hero_call_to_action_url = models.CharField(max_length=255, blank=True) hero_image = models.ForeignKey('wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+') benefits_section_title = models.CharField(max_length=255, blank=True) benefits_section_intro = models.TextField(max_length=255, blank=True) benefits_section_content = MarkdownField(blank=True) benefits_section_img = models.ForeignKey( 'wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', verbose_name="Benefits section image") eu_exit_section_title = models.CharField( max_length=255, blank=True, verbose_name="EU exit section title") eu_exit_section_content = MarkdownField( blank=True, verbose_name="EU exit section content") eu_exit_section_call_to_action_text = models.CharField( max_length=255, blank=True, verbose_name="EU exit section button text") eu_exit_section_call_to_action_url = models.CharField( max_length=255, blank=True, verbose_name="EU exit section button url") eu_exit_section_img = models.ForeignKey( 'wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', verbose_name="EU exit section image") sector_title = models.TextField(default="Discover UK Industries", max_length=255, blank=True) sector_button_text = models.TextField(default="See more industries", max_length=255, blank=True) sector_button_url = models.CharField(max_length=255, blank=True) sector_intro = models.TextField(max_length=255, blank=True) hpo_title = models.CharField( max_length=255, verbose_name="High potential opportunity section title", blank=True) hpo_intro = models.TextField( max_length=255, blank=True, verbose_name="High potential opportunity section intro") capital_invest_section_title = models.CharField(max_length=255, blank=True) capital_invest_section_content = MarkdownField(blank=True) capital_invest_section_image = models.ForeignKey('wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+') setup_guide_title = models.CharField( default='Set up an overseas business in the UK', max_length=255, blank=True) setup_guide_lead_in = models.TextField(blank=True, null=True) setup_guide_content = MarkdownField(blank=True) setup_guide_img = models.ForeignKey('wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', verbose_name="Setup guide image") setup_guide_call_to_action_url = models.CharField(max_length=255, blank=True) isd_section_image = models.ForeignKey( 'wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', verbose_name='Investment Support Directory section image') isd_section_title = models.CharField( max_length=255, blank=True, verbose_name='Investment Support Directory section title') isd_section_text = MarkdownField( max_length=255, blank=True, verbose_name='Investment Support Directory section text') featured_card_one_image = models.ForeignKey( 'wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', ) featured_card_one_title = models.CharField(blank=True, max_length=255) featured_card_one_summary = MarkdownField(blank=True) featured_card_one_cta_link = models.CharField(max_length=255, blank=True) featured_card_two_image = models.ForeignKey( 'wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+', ) featured_card_two_title = models.CharField( max_length=255, blank=True, ) featured_card_two_summary = MarkdownField( max_length=255, blank=True, ) featured_card_two_cta_link = models.CharField(max_length=255, blank=True) featured_card_three_image = models.ForeignKey('wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+') featured_card_three_title = models.CharField(max_length=255, blank=True) featured_card_three_summary = MarkdownField(blank=True) featured_card_three_cta_link = models.CharField(max_length=255, blank=True) how_we_help_title = models.CharField(default='How we help', max_length=255, blank=True) how_we_help_lead_in = models.TextField(blank=True, null=True) # how we help how_we_help_text_one = models.CharField(max_length=255, blank=True) how_we_help_icon_one = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') how_we_help_text_two = models.CharField(max_length=255, blank=True) how_we_help_icon_two = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') how_we_help_text_three = models.CharField(max_length=255, blank=True) how_we_help_icon_three = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') how_we_help_text_four = models.CharField(max_length=255, blank=True) how_we_help_icon_four = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') how_we_help_text_five = models.CharField(max_length=255, blank=True) how_we_help_icon_five = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') how_we_help_text_six = models.CharField(max_length=255, blank=True) contact_section_title = models.CharField(max_length=255, blank=True) contact_section_content = models.TextField(max_length=255, blank=True) contact_section_call_to_action_text = models.CharField(max_length=255, blank=True) contact_section_call_to_action_url = models.CharField(max_length=255, blank=True) image_panels = [ ImageChooserPanel('hero_image'), ] content_panels = [ MultiFieldPanel( heading='Hero', classname='collapsible', children=[ FieldPanel('breadcrumbs_label'), FieldPanel('heading'), FieldPanel('sub_heading'), FieldPanel('hero_call_to_action_text'), FieldPanel('hero_call_to_action_url'), ], ), MultiFieldPanel( heading='Benefits section', classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Benefits Section Title, Benefits Section Content'), FieldPanel('benefits_section_title'), FieldPanel('benefits_section_intro'), FieldPanel('benefits_section_content'), ImageChooserPanel('benefits_section_img'), ], ), MultiFieldPanel( heading='EU Exit section', classname='collapsible collapsed', children=[ FieldPanel('eu_exit_section_title'), FieldPanel('eu_exit_section_content'), FieldPanel('eu_exit_section_call_to_action_text'), FieldPanel('eu_exit_section_call_to_action_url'), ImageChooserPanel('eu_exit_section_img'), ], ), MultiFieldPanel( heading='Old featured card links', classname='collapsible collapsed', children=[ FieldRowPanel([ MultiFieldPanel([ ImageChooserPanel('setup_guide_img'), FieldPanel('setup_guide_title'), FieldPanel('setup_guide_content'), FieldPanel('setup_guide_call_to_action_url'), ], ), MultiFieldPanel([ ImageChooserPanel('isd_section_image'), FieldPanel('isd_section_title'), FieldPanel('isd_section_text') ], ), MultiFieldPanel([ ImageChooserPanel('capital_invest_section_image'), FieldPanel('capital_invest_section_title'), FieldPanel('capital_invest_section_content'), ]), ]), ], ), MultiFieldPanel( heading='Featured card links ', classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'All images, titles and summaries'), FieldRowPanel([ MultiFieldPanel([ ImageChooserPanel('featured_card_one_image'), FieldPanel('featured_card_one_title'), FieldPanel('featured_card_one_summary'), FieldPanel('featured_card_one_cta_link'), ], ), MultiFieldPanel([ ImageChooserPanel('featured_card_two_image'), FieldPanel('featured_card_two_title'), FieldPanel('featured_card_two_summary'), FieldPanel('featured_card_two_cta_link'), ], ), MultiFieldPanel([ ImageChooserPanel('featured_card_three_image'), FieldPanel('featured_card_three_title'), FieldPanel('featured_card_three_summary'), FieldPanel('featured_card_three_cta_link'), ]), ]), ], ), MultiFieldPanel( heading='Industries section', children=[ HelpPanel('Required fields for section to show: ' 'Sector Title, Sector Content'), FieldPanel('sector_title'), FieldPanel('sector_intro'), FieldPanel('sector_button_text'), FieldPanel('sector_button_url'), ], ), MultiFieldPanel( heading='High Potential Opportunities', children=[ HelpPanel('Required fields for section to show: ' 'HPO title, 1 HPO in active language'), FieldPanel('hpo_title'), FieldPanel('hpo_intro') ], ), MultiFieldPanel( heading='How we help section', classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'How We Help Title, How We Help Lead In'), FieldPanel('how_we_help_title'), FieldPanel('how_we_help_lead_in'), HelpPanel('Each icon requires the corresponding text to ' 'show on the page'), FieldRowPanel([ MultiFieldPanel([ FieldPanel('how_we_help_text_one'), ImageChooserPanel('how_we_help_icon_one') ], ), MultiFieldPanel([ FieldPanel('how_we_help_text_two'), ImageChooserPanel('how_we_help_icon_two') ], ), MultiFieldPanel([ FieldPanel('how_we_help_text_three'), ImageChooserPanel('how_we_help_icon_three') ], ), ], ), FieldRowPanel([ MultiFieldPanel([ FieldPanel('how_we_help_text_four'), ImageChooserPanel('how_we_help_icon_four') ], ), MultiFieldPanel([ FieldPanel('how_we_help_text_five'), ImageChooserPanel('how_we_help_icon_five') ], ) ], ), ], ), MultiFieldPanel( heading='Contact Section', classname='collapsible', children=[ HelpPanel('Required fields for section to show: ' 'Contact Title, Contact Content'), FieldPanel('contact_section_title'), FieldPanel('contact_section_content'), HelpPanel('Cta\'s require both text and a link to show ' 'on page. '), FieldPanel('contact_section_call_to_action_text'), FieldPanel('contact_section_call_to_action_url'), ], ), SearchEngineOptimisationPanel() ] settings_panels = [ FieldPanel('title_en_gb'), FieldPanel('slug'), ] edit_handler = make_translated_interface(content_panels=content_panels, settings_panels=settings_panels, other_panels=[ ObjectList(image_panels, heading='Images'), ])
class NavbarSection(models.Model): """ Navbar Section """ navbar_layout_scheme = models.CharField( max_length=50, choices=cr_settings['NAVBAR_LAYOUT_SCHEME_CHOICES'], default=cr_settings['NAVBAR_LAYOUT_SCHEME_CHOICES_DEFAULT'], verbose_name=('Layout Scheme'), ) navbar_color_scheme = models.CharField( max_length=50, choices=cr_settings['NAVBAR_COLOR_SCHEME_CHOICES'], default=cr_settings['NAVBAR_COLOR_SCHEME_CHOICES_DEFAULT'], verbose_name=('Color type'), ) navbar_background_type = models.CharField( blank=True, null=True, choices=cr_settings['NAVBAR_BACKGROUND_TYPE_CHOICES'], verbose_name='Type', max_length=100, ) navbar_background_color = ColorField( blank=True, null=True, verbose_name=('Color 1'), ) navbar_background_color_2 = ColorField( blank=True, null=True, verbose_name=('Color 2'), ) navbar_font_color = ColorField( blank=True, null=True, verbose_name=('Font color'), ) navbar_fixed = models.BooleanField( default=False, verbose_name=('Fixed'), ) navbar_transparent = models.BooleanField( default=False, verbose_name=('Transparent'), ) navbar_height = models.CharField( null=True, blank=True, max_length=50, choices=cr_settings['NAVBAR_HEIGHT_CHOICES'], default=cr_settings['NAVBAR_HEIGHT_CHOICES_DEFAULT'], verbose_name='Height', ) navbar_top_bottom_padding = models.CharField( null=True, blank=True, max_length=50, choices=cr_settings['NAVBAR_TOP_BOTTOM_PADDING_CHOICES'], default=cr_settings['NAVBAR_TOP_BOTTOM_PADDING_CHOICES_DEFAULT'], verbose_name='Padding', ) navbar_container_width = models.CharField( null=True, blank=True, max_length=50, choices=cr_settings['NAVBAR_CONTAINER_WIDTH_CHOICES'], default=cr_settings['NAVBAR_CONTAINER_WIDTH_CHOICES_DEFAULT'], verbose_name='Width', ) # Panels navbar_panels = ( # NAVBAR HelpPanel(template='panels/custom_help_panel_heading.html', content='Navbar'), MultiFieldPanel( ( FieldRowPanel(children=(FieldPanel('navbar_transparent', classname="col6"), ), ), FieldRowPanel(children=(FieldPanel('navbar_color_scheme', classname="col6"), ), ), FieldRowPanel(children=( FieldPanel('navbar_background_type', classname="col6"), )), FieldRowPanel(children=( NativeColorPanel('navbar_background_color', classname="col6"), NativeColorPanel('navbar_background_color_2', classname="col6"), ), ), ), heading='Design', classname='collapsible collapsed', ), MultiFieldPanel( ( FieldRowPanel(children=(FieldPanel('navbar_fixed', classname="col6"), ), ), FieldRowPanel(children=( FieldPanel('navbar_layout_scheme', classname="col6"), FieldPanel('navbar_height', classname="col6"), FieldPanel('navbar_container_width', classname="col6"), FieldPanel('navbar_top_bottom_padding', classname="col6"), ), ), ), heading='Layout', classname='collapsible collapsed', ), HelpPanel(template='panels/custom_help_panel_heading.html', content=''), ) class Meta: abstract = True