Light Realm-powered content management system
Swift Ruby
Latest commit 9d3a9cd Nov 15, 2017 @icanzilb icanzilb bump version

README.md

RealmContent

CI Status Version License Platform

This library is powered by RealmSwift ( Realm Docs ) and automatically provides a CMS capabilities to an iOS app.

Table of contents:

  1. Code Example
  2. Usage
  3. Installation
  4. Credits

Quick Showcase (~3 min)

Video Thumbnail

Links to video and blog article about RealmContent.

Code Example

The demo app in this repo includes a full working example of an app using RealmContent. Here's the crash-course:

1) Import RealmSwift and RealmContent

import RealmSwift
import RealmContent

Your app would normally have a list of objects it syncs from the Realm Object Server:

Once you import RealmContent it will expose two new models which Realm will add to your default schema.

If you're using multiple Realm files, add ContentPage and ContentElement to the desired object schema.

2) Create a content data source

To display a list of the available content in your app you can use the ContentListDataSource class that RealmContent provides you with:

let items = ContentListDataSource(style: .sectionsByTag)

Use .plain for a plain list or .sectionsByTag for a list with sections.

3) Initialize the data source

Tell the data source, which realm you will be using (this is where, in case you have more than one, you indicate which one).

items.loadContent(from: try! Realm())

You can also have the data source automatically tell your table or collection view to reload the data whenever changes come in from the Realm Object Server:

items.updating(view: tableView)

4) Implement your table view or collection view data source methods like usual, but use the content data source like so:

extension ViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return items.numberOfSections
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.numberOfItemsIn(section: section)
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return items.titleForSection(section: section)
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = items.itemAt(indexPath: indexPath)
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!

        cell.accessoryType = .disclosureIndicator
        cell.textLabel?.text = "»  \(item.title ?? "...")"

        return cell
    }
}

This will show the list of available content.

The next step is to show the "pages" of content on screen, which you do by presenting a custom view controller.

5) Presenting a content "page"

Present a ContentViewController instance to display content. You can do this from a table/collection view tap delegate method or from an arbitrary piece of code. Here's an example of how would it work after a tap on a table cell:

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)

        let item = items.itemAt(indexPath: indexPath)
        let vc = ContentViewController(page: item)

        navigationController!.pushViewController(vc, animated: true)
    }
}

The presented view controller uses a table view to dynamically show the content from the given ContentPage element. In case you change the content remotely the changes will be reflected in real-time on screen.

Which brings us to...

Usage

You work with two types of objects ContentPage and ContentElement. The former represents a news article, blog post, product page, and whatever other content you have. The latter - a piece of content within a page, this could be a paragraph of text, a heading, a sub-heading, an image, or a link.

You can create all of this content via the Realm Browser app and update the content on all your app's client devices in real-time.

Pages

You can add new ContentPage objects via the Realm Browser or from code:

  • title - the page title, used autom. in the content list (optional)
  • priority - integer used to order automatically the content (optional)
  • mainColor - an accent color for headings and links (optional)
  • lang - used by developer to filter content by language (optional)
  • tag - used by developer to filter content and automatically group in the content list (optional)
  • id - used by developer to assign id to page (optional)
  • elements - an ordered list of ContentElements

Elements

When you click (in the Realm Browser) on the elements cell you will see the content elements of the content page. You can delete, add, or re-order them (via drag'n'drop).

1) Headings

Four levels of headings from h1 to h4, which get the system heading and title font sizes, so they automatically adjust size in case your users use the usability features of iOS. The headings will automatically adopt the mainColor value (hex #004433 or named color pink) or fallback on the TextContentCell.defaultTextColor color value, which you can set from code.

2) Text and links

An element of type p creates a paragraph of text.

3) Image

An element of type img fetches an image from the web and caches it locally. The image will be downscaled when wider than the view controller's view width.

4) Links

If you set the value of the url column to a valid url address, the text or image will become tappable elements and open the target url either in a safari view controller or directly in Safari (check the docs for details).

If a link starts with the app:// scheme it will, upon a tap, call your custom URL handling closure so you have the chance to react to link taps in your app's code. Here's a quick example:

// example link: "app://cart/product/id/123"

let vc = ContentViewController(page: myContentPageObject)
vc.openCustomURL = { url in 
  if url.host == "cart" {
    myCart.addProductWithId(url.lastPathComponent)
  }
}
present(vc, animated: true)

Markdown

The library includes class for rendering Markdown content. If you're using CocoaPods make sure to include the sub-spec called RealmContent.Markdown.

MarkdownViewController is an alternative to ContentViewController; instead of using a native table view to render all elements interactively it simply uses a full-screen web view and renders all elements as markdown and/or HTML.

This approach enables you to push HTML from the server inside any ContentElement and render anything you want. You gain that at the cost of some of the performance gains for larger documents and change animations that you get with the native table view controller.

You can either use MarkdownViewController as the class of a controller in your storyboard or you can create an instance manually and present it on screen:

let vc = MarkdownViewController(page: myContentPageObject)
vc.openCustomURL = { customUrl in ... }
vc.usesSafariController = true
vc.customCssStyle = "h1 {color: purple;}"
present(vc, animated: true)

Installation

RealmContent is available through CocoaPods. To install it, simply add the following line to your Podfile:

# to include the core library
pod "RealmContent"

# or to include markdown and core
pod "RealmContent.Core"
pod "RealmContent.Markdown"

Alternatively, include the source code files directly into your own project.

Credits

License

MIT licensed.

About

The names and logos for Realm are trademarks of Realm Inc.

We ❤️ open source software!

See our other open source projects, read our blog, or say hi on twitter (@realm).

analytics