Skip to content

Commit

Permalink
Allow the user to select a feed if a Web page exports more than one.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmiw committed Nov 17, 2013
1 parent 7bcfc0d commit a77e02f
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/main/coffee/NR.API.coffee
Expand Up @@ -26,6 +26,7 @@ NR.API.AuthenticationFailed = "auth_failed"
NR.API.ValidationFailed = "validation_failed"
NR.API.ServerError = "server_error"
NR.API.NotAFeedError = "not_a_feed"
NR.API.MultipleFeedsFoundError = "multiple_feeds_found"

NR.API.httpErrorCodeList = {
401: NR.API.AuthenticationFailed
Expand Down
3 changes: 3 additions & 0 deletions src/main/coffee/NR.Models.coffee
Expand Up @@ -5,6 +5,9 @@ else

NR.Models = {}

class NR.Models.MultipleFeedEntry extends SimpleMVC.Model
@fields "title", "url"

class NR.Models.CreateFeedModel extends SimpleMVC.Model
@fields "baseUrl", "baseHtml", "xpathTitle", "xpathLink", "xpathBody"

Expand Down
28 changes: 28 additions & 0 deletions src/main/coffee/NR.Views.coffee
Expand Up @@ -172,6 +172,34 @@ class NR.Views.NewsFeedListing extends SimpleMVC.CollectionView
window.app.deselectFeed()
e.preventDefault()

class NR.Views.MultipleFeedEntry extends SimpleMVC.View
@tag "div"
@class "radio"
this.prototype.template = Mustache.compile $("#template-multipleFeedEntry").html()

class NR.Views.MultipleFeedsFoundWindow extends SimpleMVC.CollectionView
@hideOnStart true
@id "multipleFeedsFound"
@listClass "multipleFeedList"
@viewType NR.Views.MultipleFeedEntry
this.prototype.template = Mustache.compile $("#template-multipleFeedsListing").html()

@event "click", "#addMultipleFeedButton", () ->
if not $("#addMultipleFeedButton").hasClass "disabled"
selectedUrl = $('input:radio[name=aMultipleFeedEntry]:checked').val();
window.app.addFeed selectedUrl
this.hide()

@event "click", "input:radio[name=aMultipleFeedEntry]", () ->
# Enable Add button.
$("#addMultipleFeedButton").removeClass "disabled"

show: () =>
this.domObject.modal()

hide: () =>
this.domObject.modal('hide')

class NR.Views.CreateFeedWindow extends SimpleMVC.View
@id "createFeed"
@hideOnStart true
Expand Down
11 changes: 10 additions & 1 deletion src/main/coffee/main.coffee
Expand Up @@ -28,10 +28,19 @@ class NR.Application extends SimpleMVC.Controller
feedModel.baseUrl = $("#addFeedUrl").val()
this._createFeedView.model = feedModel
this._createFeedView.show()
else if desc == NR.API.MultipleFeedsFoundError
foundList = new SimpleMVC.Collection
this._multipleFeedFoundView = new NR.Views.MultipleFeedsFoundWindow foundList
this._multipleFeedFoundView.show()
for i in data
entry = new NR.Models.MultipleFeedEntry
entry.title = i.title
entry.url = i.url
foundList.add entry
else
errorText = "The server encountered an error while processing the request. Please try again."

if desc != NR.API.NotAFeedError
if desc != NR.API.NotAFeedError && desc != NR.API.MultipleFeedsFoundError
noty({ text: errorText, layout: "topRight", timeout: 2000, dismissQueue: true, type: "error" });

@route "saved/:uid", (uid) ->
Expand Down
7 changes: 5 additions & 2 deletions src/main/scala/us/newsrdr/models/ApiResult.scala
Expand Up @@ -35,13 +35,16 @@ object Constants {
class ApiResult(success: Boolean, error_string: Option[String])

case class StringDataApiResult(success: Boolean, error_string: Option[String], data: String)
extends ApiResult(success, error_string)
extends ApiResult(success, error_string)

case class AddFeedListApiResult(success: Boolean, error_string: Option[String], data: List[AddFeedEntry])
extends ApiResult(success, error_string)

case class NoDataApiResult(success: Boolean, error_string: Option[String])
extends ApiResult(success, error_string)

case class FeedInfoApiResult(success: Boolean, error_string: Option[String], data: NewsFeedInfo)
extends ApiResult(success, error_string)
extends ApiResult(success, error_string)

case class FeedListApiResult(success: Boolean, error_string: Option[String], data: List[NewsFeedInfo])
extends ApiResult(success, error_string)
Expand Down
16 changes: 15 additions & 1 deletion src/main/scala/us/newsrdr/models/NewsFeed.scala
Expand Up @@ -159,6 +159,11 @@ class ManualCloseBufferedStream(s: java.io.InputStream) extends java.io.Buffered
}

class HasNoFeedsException(text: String) extends Exception(text) { }
case class AddFeedEntry(title: String, url: String)
class MultipleFeedsException(feedList: List[AddFeedEntry]) extends Exception
{
def getFeedList = feedList
}

object XmlFeedFactory {
val parser = XML.withSAXParser(new org.ccil.cowan.tagsoup.jaxp.SAXFactoryImpl().newSAXParser())
Expand Down Expand Up @@ -375,10 +380,19 @@ object XmlFeedFactory {
val feedLinks = (xmlDoc \\ "link").filter(attributeEquals("rel", "alternate")(_))
.filter(x => attributeEquals("type", "application/rss+xml")(x) ||
attributeEquals("type", "application/atom+xml")(x))
if (feedLinks.count(_ => true) > 0 && !feedLinks.head.attribute("href").map(_.text).head.equals(url))
val feedCount = feedLinks.count(_ => true)
if (feedCount == 1 && !feedLinks.head.attribute("href").map(_.text).head.equals(url))
{
load(new java.net.URL(new java.net.URL(currentUrl), feedLinks.head.attribute("href").map(_.text).head).toString())
}
else if (feedCount > 1)
{
// Return list of RSS feeds for user to choose from.
throw new MultipleFeedsException(
feedLinks.map(p => AddFeedEntry(
p.attribute("title").map(_.text).head,
p.attribute("href").map(_.text).head)).toList)
}
else
{
val feed =
Expand Down
3 changes: 3 additions & 0 deletions src/main/scala/us/newsrdr/servlet/FeedServlet.scala
Expand Up @@ -240,6 +240,9 @@ class FeedServlet(dao: DataTables, db: Database, implicit val swagger: Swagger)
// need to do this because of XSS restrictions on the client side.
StringDataApiResult(false, Some("not_a_feed"), e.getMessage())
}
case e:MultipleFeedsException => {
AddFeedListApiResult(false, Some("multiple_feeds_found"), e.getFeedList)
}
}
}
}, {
Expand Down
35 changes: 34 additions & 1 deletion src/main/webapp/WEB-INF/templates/views/app.ssp
Expand Up @@ -91,6 +91,10 @@
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->

<div class="modal fade" id="multipleFeedsFound" tabindex="-1" role="dialog" aria-labelledby="multipleFeedsFound" aria-hidden="true">

</div><!-- /.modal -->

<div class="modal fade" id="createFeed" tabindex="-1" role="dialog" aria-labelledby="createFeedLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
Expand Down Expand Up @@ -167,7 +171,36 @@
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->


<script type="text/template" id="template-multipleFeedsListing">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Multiple Feeds Found</h4>
</div>
<div class="modal-body">
<p>
The Web page provided exports multiple feeds. Please choose one below to add:
</p>
<p class="multipleFeedList">
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary disabled" id="addMultipleFeedButton">Add</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</script>

<script type="text/template" id="template-multipleFeedEntry">
<label>
<input type="radio" name="aMultipleFeedEntry" value="{{url}}" />
{{title}}
</label>
</script>

<script type="text/template" id="template-topNavBar">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
Expand Down

0 comments on commit a77e02f

Please sign in to comment.