Skip to content

Commit a77e02f

Browse files
committed
Allow the user to select a feed if a Web page exports more than one.
1 parent 7bcfc0d commit a77e02f

File tree

8 files changed

+99
-5
lines changed

8 files changed

+99
-5
lines changed

src/main/coffee/NR.API.coffee

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ NR.API.AuthenticationFailed = "auth_failed"
2626
NR.API.ValidationFailed = "validation_failed"
2727
NR.API.ServerError = "server_error"
2828
NR.API.NotAFeedError = "not_a_feed"
29+
NR.API.MultipleFeedsFoundError = "multiple_feeds_found"
2930

3031
NR.API.httpErrorCodeList = {
3132
401: NR.API.AuthenticationFailed

src/main/coffee/NR.Models.coffee

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ else
55

66
NR.Models = {}
77

8+
class NR.Models.MultipleFeedEntry extends SimpleMVC.Model
9+
@fields "title", "url"
10+
811
class NR.Models.CreateFeedModel extends SimpleMVC.Model
912
@fields "baseUrl", "baseHtml", "xpathTitle", "xpathLink", "xpathBody"
1013

src/main/coffee/NR.Views.coffee

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,34 @@ class NR.Views.NewsFeedListing extends SimpleMVC.CollectionView
172172
window.app.deselectFeed()
173173
e.preventDefault()
174174

175+
class NR.Views.MultipleFeedEntry extends SimpleMVC.View
176+
@tag "div"
177+
@class "radio"
178+
this.prototype.template = Mustache.compile $("#template-multipleFeedEntry").html()
179+
180+
class NR.Views.MultipleFeedsFoundWindow extends SimpleMVC.CollectionView
181+
@hideOnStart true
182+
@id "multipleFeedsFound"
183+
@listClass "multipleFeedList"
184+
@viewType NR.Views.MultipleFeedEntry
185+
this.prototype.template = Mustache.compile $("#template-multipleFeedsListing").html()
186+
187+
@event "click", "#addMultipleFeedButton", () ->
188+
if not $("#addMultipleFeedButton").hasClass "disabled"
189+
selectedUrl = $('input:radio[name=aMultipleFeedEntry]:checked').val();
190+
window.app.addFeed selectedUrl
191+
this.hide()
192+
193+
@event "click", "input:radio[name=aMultipleFeedEntry]", () ->
194+
# Enable Add button.
195+
$("#addMultipleFeedButton").removeClass "disabled"
196+
197+
show: () =>
198+
this.domObject.modal()
199+
200+
hide: () =>
201+
this.domObject.modal('hide')
202+
175203
class NR.Views.CreateFeedWindow extends SimpleMVC.View
176204
@id "createFeed"
177205
@hideOnStart true

src/main/coffee/main.coffee

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,19 @@ class NR.Application extends SimpleMVC.Controller
2828
feedModel.baseUrl = $("#addFeedUrl").val()
2929
this._createFeedView.model = feedModel
3030
this._createFeedView.show()
31+
else if desc == NR.API.MultipleFeedsFoundError
32+
foundList = new SimpleMVC.Collection
33+
this._multipleFeedFoundView = new NR.Views.MultipleFeedsFoundWindow foundList
34+
this._multipleFeedFoundView.show()
35+
for i in data
36+
entry = new NR.Models.MultipleFeedEntry
37+
entry.title = i.title
38+
entry.url = i.url
39+
foundList.add entry
3140
else
3241
errorText = "The server encountered an error while processing the request. Please try again."
3342

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

3746
@route "saved/:uid", (uid) ->

src/main/scala/us/newsrdr/models/ApiResult.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ object Constants {
3535
class ApiResult(success: Boolean, error_string: Option[String])
3636

3737
case class StringDataApiResult(success: Boolean, error_string: Option[String], data: String)
38-
extends ApiResult(success, error_string)
38+
extends ApiResult(success, error_string)
39+
40+
case class AddFeedListApiResult(success: Boolean, error_string: Option[String], data: List[AddFeedEntry])
41+
extends ApiResult(success, error_string)
3942

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

4346
case class FeedInfoApiResult(success: Boolean, error_string: Option[String], data: NewsFeedInfo)
44-
extends ApiResult(success, error_string)
47+
extends ApiResult(success, error_string)
4548

4649
case class FeedListApiResult(success: Boolean, error_string: Option[String], data: List[NewsFeedInfo])
4750
extends ApiResult(success, error_string)

src/main/scala/us/newsrdr/models/NewsFeed.scala

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ class ManualCloseBufferedStream(s: java.io.InputStream) extends java.io.Buffered
159159
}
160160

161161
class HasNoFeedsException(text: String) extends Exception(text) { }
162+
case class AddFeedEntry(title: String, url: String)
163+
class MultipleFeedsException(feedList: List[AddFeedEntry]) extends Exception
164+
{
165+
def getFeedList = feedList
166+
}
162167

163168
object XmlFeedFactory {
164169
val parser = XML.withSAXParser(new org.ccil.cowan.tagsoup.jaxp.SAXFactoryImpl().newSAXParser())
@@ -375,10 +380,19 @@ object XmlFeedFactory {
375380
val feedLinks = (xmlDoc \\ "link").filter(attributeEquals("rel", "alternate")(_))
376381
.filter(x => attributeEquals("type", "application/rss+xml")(x) ||
377382
attributeEquals("type", "application/atom+xml")(x))
378-
if (feedLinks.count(_ => true) > 0 && !feedLinks.head.attribute("href").map(_.text).head.equals(url))
383+
val feedCount = feedLinks.count(_ => true)
384+
if (feedCount == 1 && !feedLinks.head.attribute("href").map(_.text).head.equals(url))
379385
{
380386
load(new java.net.URL(new java.net.URL(currentUrl), feedLinks.head.attribute("href").map(_.text).head).toString())
381387
}
388+
else if (feedCount > 1)
389+
{
390+
// Return list of RSS feeds for user to choose from.
391+
throw new MultipleFeedsException(
392+
feedLinks.map(p => AddFeedEntry(
393+
p.attribute("title").map(_.text).head,
394+
p.attribute("href").map(_.text).head)).toList)
395+
}
382396
else
383397
{
384398
val feed =

src/main/scala/us/newsrdr/servlet/FeedServlet.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ class FeedServlet(dao: DataTables, db: Database, implicit val swagger: Swagger)
240240
// need to do this because of XSS restrictions on the client side.
241241
StringDataApiResult(false, Some("not_a_feed"), e.getMessage())
242242
}
243+
case e:MultipleFeedsException => {
244+
AddFeedListApiResult(false, Some("multiple_feeds_found"), e.getFeedList)
245+
}
243246
}
244247
}
245248
}, {

src/main/webapp/WEB-INF/templates/views/app.ssp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@
9191
</div><!-- /.modal-dialog -->
9292
</div><!-- /.modal -->
9393

94+
<div class="modal fade" id="multipleFeedsFound" tabindex="-1" role="dialog" aria-labelledby="multipleFeedsFound" aria-hidden="true">
95+
96+
</div><!-- /.modal -->
97+
9498
<div class="modal fade" id="createFeed" tabindex="-1" role="dialog" aria-labelledby="createFeedLabel" aria-hidden="true">
9599
<div class="modal-dialog">
96100
<div class="modal-content">
@@ -167,7 +171,36 @@
167171
</div><!-- /.modal-content -->
168172
</div><!-- /.modal-dialog -->
169173
</div><!-- /.modal -->
170-
174+
175+
<script type="text/template" id="template-multipleFeedsListing">
176+
<div class="modal-dialog">
177+
<div class="modal-content">
178+
<div class="modal-header">
179+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
180+
<h4 class="modal-title">Multiple Feeds Found</h4>
181+
</div>
182+
<div class="modal-body">
183+
<p>
184+
The Web page provided exports multiple feeds. Please choose one below to add:
185+
</p>
186+
<p class="multipleFeedList">
187+
</p>
188+
</div>
189+
<div class="modal-footer">
190+
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
191+
<button type="button" class="btn btn-primary disabled" id="addMultipleFeedButton">Add</button>
192+
</div>
193+
</div><!-- /.modal-content -->
194+
</div><!-- /.modal-dialog -->
195+
</script>
196+
197+
<script type="text/template" id="template-multipleFeedEntry">
198+
<label>
199+
<input type="radio" name="aMultipleFeedEntry" value="{{url}}" />
200+
{{title}}
201+
</label>
202+
</script>
203+
171204
<script type="text/template" id="template-topNavBar">
172205
<div class="navbar-header">
173206
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">

0 commit comments

Comments
 (0)