diff --git a/src/c3nav/mapdata/models/level.py b/src/c3nav/mapdata/models/level.py index c0c3f824..5c10dcbb 100644 --- a/src/c3nav/mapdata/models/level.py +++ b/src/c3nav/mapdata/models/level.py @@ -92,5 +92,6 @@ class Level(SpecificLocation, models.Model): return unary_union(tuple(item.geometry.buffer(0) for item in chain(self.altitudeareas.all(), self.buildings.all()))).bounds - def get_icon(self): - return super().get_icon() or 'layers' + @property + def effective_icon(self): + return super().effective_icon or 'layers' diff --git a/src/c3nav/mapdata/models/locations.py b/src/c3nav/mapdata/models/locations.py index 1b8f1b50..f7236653 100644 --- a/src/c3nav/mapdata/models/locations.py +++ b/src/c3nav/mapdata/models/locations.py @@ -124,25 +124,19 @@ class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model): result = {name: result[name] for name in fields if name in result} return result - def _serialize(self, search=False, **kwargs): - result = super()._serialize(**kwargs) - result['subtitle'] = self.subtitle - result['icon'] = self.get_icon() - result['can_search'] = self.can_search - result['can_describe'] = self.can_search - if search: - result['add_search'] = ' '.join(( - *(redirect.slug for redirect in self.redirects.all()), - *self.other_titles, - )) - return result + @property + def add_search(self): + return ' '.join(( + *(redirect.slug for redirect in self.redirects.all()), + *self.other_titles, + )) def details_display(self, **kwargs): result = super().details_display(**kwargs) result['display'].extend([ (_('searchable'), _('Yes') if self.can_search else _('No')), (_('can describe'), _('Yes') if self.can_describe else _('No')), - (_('icon'), self.get_icon()), + (_('icon'), self.effective_icon), ]) return result @@ -175,7 +169,8 @@ class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model): return (0, group.category.priority, group.hierarchy, group.priority), color return None - def get_icon(self): + @property + def effective_icon(self): return self.icon or None @@ -281,8 +276,9 @@ class SpecificLocation(Location, models.Model): return (0, 0, 0) return (0, groups[0].category.priority, groups[0].priority) - def get_icon(self): - icon = super().get_icon() + @property + def effective_icon(self): + icon = super().effective_icon if icon: return icon for group in self.groups.all(): @@ -554,7 +550,7 @@ class DynamicLocation(CustomLocationProxyMixin, SpecificLocation, models.Model): 'available': False, 'id': self.pk, 'slug': self.slug, - 'icon': self.get_icon(), + 'icon': self.effective_icon, 'title': str(self.title), 'subtitle': '%s %s, %s' % (_('currently unavailable'), _('(moving)'), self.subtitle) } @@ -563,7 +559,7 @@ class DynamicLocation(CustomLocationProxyMixin, SpecificLocation, models.Model): 'available': True, 'id': self.pk, 'slug': self.slug, - 'icon': self.get_icon(), + 'icon': self.effective_icon, 'title': str(self.title), 'subtitle': '%s %s%s, %s' % ( _('(moving)'), diff --git a/src/c3nav/mapdata/schemas/model_base.py b/src/c3nav/mapdata/schemas/model_base.py index 93915785..dfdedab6 100644 --- a/src/c3nav/mapdata/schemas/model_base.py +++ b/src/c3nav/mapdata/schemas/model_base.py @@ -96,8 +96,13 @@ class LocationSchema(WithAccessRestrictionSchema, TitledSchema, LocationSlugSche example="near Area 51", ) icon: Optional[NonEmptyStr] = APIField( # todo: not optional? - title="icon name", - description="any material design icon name", + title="set icon name", + description="as set in the object specifically (any material design icon name)", + example="pin_drop", + ) + effective_icon: Optional[NonEmptyStr] = APIField( # todo: not optional? + title="icon name to use", + description="effective icon to use (any material design icon name)", example="pin_drop", ) can_search: bool = APIField( diff --git a/src/c3nav/mapdata/schemas/models.py b/src/c3nav/mapdata/schemas/models.py index 470f9a7b..34be2f74 100644 --- a/src/c3nav/mapdata/schemas/models.py +++ b/src/c3nav/mapdata/schemas/models.py @@ -387,8 +387,13 @@ class CustomLocationSchema(BaseSchema): description="slug, identical to ID" ) icon: Optional[NonEmptyStr] = APIField( # todo: not optional? - title="icon name", - description="any material design icon name", + title="set icon name", + description="as set in the object specifically (any material design icon name)", + example="pin_drop", + ) + effective_icon: Optional[NonEmptyStr] = APIField( # todo: not optional? + title="icon name to use", + description="effective icon to use (any material design icon name)", example="pin_drop", ) title: NonEmptyStr = APIField( @@ -470,8 +475,13 @@ class TrackablePositionSchema(BaseSchema): example="p:adskjfalskdj", ) icon: Optional[NonEmptyStr] = APIField( # todo: not optional? - title="icon name", - description="any material design icon name", + title="set icon name", + description="icon as set in the location specifically (any material design icon name)", + example="pin_drop", + ) + effective_icon: Optional[NonEmptyStr] = APIField( # todo: not optional? + title="icon name to use", + description="effective icon to use (any material design icon name)", example="pin_drop", ) title: NonEmptyStr = APIField( diff --git a/src/c3nav/mapdata/utils/locations.py b/src/c3nav/mapdata/utils/locations.py index f3313779..7b3a643c 100644 --- a/src/c3nav/mapdata/utils/locations.py +++ b/src/c3nav/mapdata/utils/locations.py @@ -458,7 +458,8 @@ class CustomLocation: def subtitle(self): return self.title_subtitle[1] - def get_icon(self): + @property + def effective_icon(self): return self.icon @property diff --git a/src/c3nav/site/static/site/js/c3nav.js b/src/c3nav/site/static/site/js/c3nav.js index d59fc445..72523e9d 100644 --- a/src/c3nav/site/static/site/js/c3nav.js +++ b/src/c3nav/site/static/site/js/c3nav.js @@ -969,7 +969,7 @@ c3nav = { }, _build_location_html: function (location) { var html = $('