apply prettier

This commit is contained in:
Athou
2022-01-01 21:26:02 +01:00
parent 0b3888a8ae
commit 0a97f04257
39 changed files with 4702 additions and 4057 deletions

7
.prettierrc Normal file
View File

@@ -0,0 +1,7 @@
{
"printWidth": 140,
"semi": false,
"tabWidth": 4,
"arrowParens": "avoid",
"endOfLine": "auto"
}

View File

@@ -1,35 +1,35 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Swagger UI</title> <title>Swagger UI</title>
<link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/> <link href="css/typography.css" media="screen" rel="stylesheet" type="text/css" />
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/> <link href="css/reset.css" media="screen" rel="stylesheet" type="text/css" />
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/> <link href="css/screen.css" media="screen" rel="stylesheet" type="text/css" />
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/> <link href="css/reset.css" media="print" rel="stylesheet" type="text/css" />
<link href='css/screen.css' media='print' rel='stylesheet' type='text/css'/> <link href="css/screen.css" media="print" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="lib/shred.bundle.js"></script> <script type="text/javascript" src="lib/shred.bundle.js"></script>
<script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script> <script src="lib/jquery-1.8.0.min.js" type="text/javascript"></script>
<script src='lib/jquery.slideto.min.js' type='text/javascript'></script> <script src="lib/jquery.slideto.min.js" type="text/javascript"></script>
<script src='lib/jquery.wiggle.min.js' type='text/javascript'></script> <script src="lib/jquery.wiggle.min.js" type="text/javascript"></script>
<script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script> <script src="lib/jquery.ba-bbq.min.js" type="text/javascript"></script>
<script src='lib/handlebars-2.0.0.js' type='text/javascript'></script> <script src="lib/handlebars-2.0.0.js" type="text/javascript"></script>
<script src='lib/underscore-min.js' type='text/javascript'></script> <script src="lib/underscore-min.js" type="text/javascript"></script>
<script src='lib/backbone-min.js' type='text/javascript'></script> <script src="lib/backbone-min.js" type="text/javascript"></script>
<script src='lib/swagger-client.js' type='text/javascript'></script> <script src="lib/swagger-client.js" type="text/javascript"></script>
<script src='swagger-ui.js' type='text/javascript'></script> <script src="swagger-ui.js" type="text/javascript"></script>
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script> <script src="lib/highlight.7.3.pack.js" type="text/javascript"></script>
<script src='lib/marked.js' type='text/javascript'></script> <script src="lib/marked.js" type="text/javascript"></script>
<!-- enabling this will enable oauth2 implicit scope support --> <!-- enabling this will enable oauth2 implicit scope support -->
<script src='lib/swagger-oauth.js' type='text/javascript'></script> <script src="lib/swagger-oauth.js" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(function () {
window.swaggerUi = new SwaggerUi({ window.swaggerUi = new SwaggerUi({
url: "./swagger.json", url: "./swagger.json",
dom_id: "swagger-ui-container", dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete'], supportedSubmitMethods: ["get", "post", "put", "delete"],
onComplete: function(swaggerApi, swaggerUi){ onComplete: function (swaggerApi, swaggerUi) {
if(typeof initOAuth == "function") { if (typeof initOAuth == "function") {
/* /*
initOAuth({ initOAuth({
clientId: "your-client-id", clientId: "your-client-id",
@@ -38,49 +38,49 @@
}); });
*/ */
} }
$('pre code').each(function(i, e) { $("pre code").each(function (i, e) {
hljs.highlightBlock(e) hljs.highlightBlock(e)
}); })
}, },
onFailure: function(data) { onFailure: function (data) {
log("Unable to Load SwaggerUI"); log("Unable to Load SwaggerUI")
}, },
docExpansion: "none", docExpansion: "none",
sorter : "alpha" sorter: "alpha",
}); })
$('#input_apiKey').change(function() { $("#input_apiKey").change(function () {
var key = $('#input_apiKey')[0].value; var key = $("#input_apiKey")[0].value
log("key: " + key); log("key: " + key)
if(key && key.trim() != "") { if (key && key.trim() != "") {
log("added key " + key); log("added key " + key)
window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "query")); window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "query"))
} }
}) })
window.swaggerUi.load(); window.swaggerUi.load()
}); })
</script> </script>
</head> </head>
<body class="swagger-section"> <body class="swagger-section">
<div id='header'> <div id="header">
<div class="swagger-ui-wrap"> <div class="swagger-ui-wrap">
<a id="logo" href="http://swagger.wordnik.com">swagger</a> <a id="logo" href="http://swagger.wordnik.com">swagger</a>
<form id='api_selector'> <form id="api_selector">
<div class='input icon-btn'> <div class="input icon-btn">
<img id="show-pet-store-icon" src="images/pet_store_api.png" title="Show Swagger Petstore Example Apis"> <img id="show-pet-store-icon" src="images/pet_store_api.png" title="Show Swagger Petstore Example Apis" />
</div> </div>
<div class='input icon-btn'> <div class="input icon-btn">
<img id="show-wordnik-dev-icon" src="images/wordnik_api.png" title="Show Wordnik Developer Apis"> <img id="show-wordnik-dev-icon" src="images/wordnik_api.png" title="Show Wordnik Developer Apis" />
</div> </div>
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div> <div class="input"><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text" /></div>
<div class='input'><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div> <div class="input"><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text" /></div>
<div class='input'><a id="explore" href="#">Explore</a></div> <div class="input"><a id="explore" href="#">Explore</a></div>
</form> </form>
</div> </div>
</div> </div>
<div id="message-bar" class="swagger-ui-wrap">&nbsp;</div> <div id="message-bar" class="swagger-ui-wrap">&nbsp;</div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div> <div id="swagger-ui-container" class="swagger-ui-wrap"></div>
</body> </body>
</html> </html>

View File

@@ -1,45 +1,45 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>CommaFeed</title> <title>CommaFeed</title>
<meta charset="utf-8"> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default"> <meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes" />
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" /> <link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<link rel="apple-touch-icon" href="app-icon-57.png" /> <link rel="apple-touch-icon" href="app-icon-57.png" />
<link rel="apple-touch-icon" sizes="72x72" href="app-icon-72.png" /> <link rel="apple-touch-icon" sizes="72x72" href="app-icon-72.png" />
<link rel="apple-touch-icon" sizes="114x114" href="app-icon-114.png" /> <link rel="apple-touch-icon" sizes="114x114" href="app-icon-114.png" />
<link rel="apple-touch-icon" sizes="144x144" href="app-icon-144.png" /> <link rel="apple-touch-icon" sizes="144x144" href="app-icon-144.png" />
<link rel="icon" sizes="32x32" href="app-icon-32.png" /> <link rel="icon" sizes="32x32" href="app-icon-32.png" />
<link rel="icon" sizes="64x64" href="app-icon-64.png" /> <link rel="icon" sizes="64x64" href="app-icon-64.png" />
<link rel="icon" sizes="128x128" href="app-icon-128.png" /> <link rel="icon" sizes="128x128" href="app-icon-128.png" />
<link rel="icon" sizes="192x192" href="app-icon-192.png" /> <link rel="icon" sizes="192x192" href="app-icon-192.png" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" /> <link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<meta name="theme-color" content="#F88A14" /> <meta name="theme-color" content="#F88A14" />
<meta name="application-name" content="CommaFeed" /> <meta name="application-name" content="CommaFeed" />
<meta name="msapplication-navbutton-color" content="#F88A14" /> <meta name="msapplication-navbutton-color" content="#F88A14" />
<meta name="msapplication-starturl" content="/" /> <meta name="msapplication-starturl" content="/" />
<meta name="msapplication-square70x70logo" content="metro-icon-70.png" /> <meta name="msapplication-square70x70logo" content="metro-icon-70.png" />
<meta name="msapplication-square150x150logo" content="metro-icon-150.png" /> <meta name="msapplication-square150x150logo" content="metro-icon-150.png" />
<link rel="fluid-icon" href="app-icon-512.png" title="CommaFeed" /> <link rel="fluid-icon" href="app-icon-512.png" title="CommaFeed" />
<link rel="logo" type="image/svg" href="app-icon.svg" /> <link rel="logo" type="image/svg" href="app-icon.svg" />
<!-- build:css css/app.css --> <!-- build:css css/app.css -->
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="lib/font-awesome/css/font-awesome.css" /> <link rel="stylesheet" href="lib/font-awesome/css/font-awesome.css" />
<link rel="stylesheet" href="lib/select2/select2.css" /> <link rel="stylesheet" href="lib/select2/select2.css" />
<link rel="stylesheet" href="lib/ng-grid/ng-grid.css" /> <link rel="stylesheet" href="lib/ng-grid/ng-grid.css" />
<link rel="stylesheet" href="lib/jquery-ui/themes/base/jquery-ui.css" /> <link rel="stylesheet" href="lib/jquery-ui/themes/base/jquery-ui.css" />
<link rel="stylesheet" href="lib/angular-loading-bar/build/loading-bar.css" /> <link rel="stylesheet" href="lib/angular-loading-bar/build/loading-bar.css" />
<link rel="stylesheet" href="css/app.css" /> <link rel="stylesheet" href="css/app.css" />
<!-- endbuild --> <!-- endbuild -->
<link rel="stylesheet" href="custom_css.css" /> <link rel="stylesheet" href="custom_css.css" />
</head> </head>
<body> <body>
<div ng-app="commafeed" id="main" class="main"> <div ng-app="commafeed" id="main" class="main">
<div ui-view></div> <div ui-view></div>
</div> </div>
@@ -82,5 +82,5 @@
<script type="text/javascript" src="js/templates.js"></script> <script type="text/javascript" src="js/templates.js"></script>
<!-- endbuild --> <!-- endbuild -->
<script type="text/javascript" src="analytics.js"></script> <script type="text/javascript" src="analytics.js"></script>
</body> </body>
</html> </html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,373 +1,402 @@
var module = angular.module('commafeed.directives', []); var module = angular.module("commafeed.directives", [])
module.directive('focus', ['$timeout', function($timeout) { module.directive("focus", [
"$timeout",
function ($timeout) {
return { return {
restrict : 'A', restrict: "A",
link : function(scope, element, attrs) { link: function (scope, element, attrs) {
scope.$watch(attrs.focus, function(value) { scope.$watch(attrs.focus, function (value) {
if (!value) if (!value) return
return; $timeout(function () {
$timeout(function() { $(element).focus()
$(element).focus(); })
}); })
}); },
} }
}; },
}]); ])
module.directive('confirmClick', [function() { module.directive("confirmClick", [
function () {
return { return {
priority : -1, priority: -1,
restrict : 'A', restrict: "A",
link : function(scope, element, attrs) { link: function (scope, element, attrs) {
element.bind('click', function(e) { element.bind("click", function (e) {
var message = scope.$eval(attrs.confirmClick); var message = scope.$eval(attrs.confirmClick)
if (message && !confirm(message)) { if (message && !confirm(message)) {
e.stopImmediatePropagation(); e.stopImmediatePropagation()
e.preventDefault(); e.preventDefault()
} }
}); })
},
} }
}; },
}]); ])
/** /**
* Open a popup window pointing to the url in the href attribute * Open a popup window pointing to the url in the href attribute
*/ */
module.directive('popup', function() { module.directive("popup", function () {
var opts = 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=800'; var opts = "menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=800"
return { return {
link : function(scope, elm, attrs) { link: function (scope, elm, attrs) {
elm.bind('click', function(event) { elm.bind("click", function (event) {
window.open(this.href, '', opts); window.open(this.href, "", opts)
event.preventDefault(); event.preventDefault()
}); })
},
} }
}; })
});
/** /**
* entry tag handling * entry tag handling
*/ */
module.directive('tags', function() { module.directive("tags", function () {
return { return {
restrict : 'E', restrict: "E",
scope : { scope: {
entry : '=' entry: "=",
}, },
replace : true, replace: true,
templateUrl : 'templates/_tags.html', templateUrl: "templates/_tags.html",
controller : ['$scope', 'EntryService', function($scope, EntryService) { controller: [
"$scope",
"EntryService",
function ($scope, EntryService) {
$scope.select2Options = { $scope.select2Options = {
'multiple' : true, multiple: true,
'simple_tags' : true, simple_tags: true,
'maximumInputLength' : 40, maximumInputLength: 40,
tags : EntryService.tags tags: EntryService.tags,
}; }
$scope.$watch('entry.tags', function(newValue, oldValue) { $scope.$watch(
"entry.tags",
function (newValue, oldValue) {
if (oldValue && newValue != oldValue) { if (oldValue && newValue != oldValue) {
var data = { var data = {
entryId : $scope.entry.id, entryId: $scope.entry.id,
tags : [] tags: [],
}; }
if (newValue) { if (newValue) {
data.tags = newValue; data.tags = newValue
} }
EntryService.tag(data); EntryService.tag(data)
} }
}, true); },
}] true
}; )
}); },
],
}
})
/** /**
* Reusable favicon component * Reusable favicon component
*/ */
module.directive('favicon', function() { module.directive("favicon", function () {
var tpl = '<img ng-src="{{url}}" class="favicon"></img>'; var tpl = '<img ng-src="{{url}}" class="favicon"></img>'
return { return {
restrict : 'E', restrict: "E",
scope : { scope: {
url : '=' url: "=",
}, },
replace : true, replace: true,
template : tpl template: tpl,
}; }
}); })
/** /**
* Support for the blur event * Support for the blur event
*/ */
module.directive('ngBlur', function() { module.directive("ngBlur", function () {
return { return {
restrict : 'A', restrict: "A",
link : function(scope, elm, attrs) { link: function (scope, elm, attrs) {
elm.bind('blur', function() { elm.bind("blur", function () {
scope.$apply(attrs.ngBlur); scope.$apply(attrs.ngBlur)
}); })
},
} }
}; })
});
/** /**
* Prevent mousewheel scrolling from propagating to the parent when scrollbar * Prevent mousewheel scrolling from propagating to the parent when scrollbar
* reaches top or bottom * reaches top or bottom
*/ */
module.directive('mousewheelScrolling', function() { module.directive("mousewheelScrolling", function () {
return { return {
restrict : 'A', restrict: "A",
link : function(scope, elem, attr) { link: function (scope, elem, attr) {
elem.bind('mousewheel', function(e, d) { elem.bind("mousewheel", function (e, d) {
var t = $(this); var t = $(this)
if (d > 0 && t.scrollTop() === 0) { if (d > 0 && t.scrollTop() === 0) {
e.preventDefault(); e.preventDefault()
} else { } else {
if (d < 0 && (t.scrollTop() == t.get(0).scrollHeight - t.innerHeight())) { if (d < 0 && t.scrollTop() == t.get(0).scrollHeight - t.innerHeight()) {
e.preventDefault(); e.preventDefault()
} }
} }
}); })
},
} }
}; })
});
/** /**
* Needed to use recursive directives. Wrap a recursive element with a * Needed to use recursive directives. Wrap a recursive element with a
* <recursive> tag * <recursive> tag
*/ */
module.directive('recursive', ['$compile', function($compile) { module.directive("recursive", [
"$compile",
function ($compile) {
return { return {
restrict : 'E', restrict: "E",
priority : 100000, priority: 100000,
compile : function(tElement, tAttr) { compile: function (tElement, tAttr) {
var contents = tElement.contents().remove(); var contents = tElement.contents().remove()
var compiledContents = null; var compiledContents = null
return function(scope, iElement, iAttr) { return function (scope, iElement, iAttr) {
if (!compiledContents) { if (!compiledContents) {
compiledContents = $compile(contents); compiledContents = $compile(contents)
} }
iElement.append(compiledContents(scope, function(clone) { iElement.append(
return clone; compiledContents(scope, function (clone) {
})); return clone
}; })
)
} }
}; },
}]); }
},
])
/** /**
* Reusable category component * Reusable category component
*/ */
module.directive('category', [function() { module.directive("category", [
function () {
return { return {
scope : { scope: {
node : '=', node: "=",
level : '=', level: "=",
selectedType : '=', selectedType: "=",
selectedId : '=', selectedId: "=",
showLabel : '=', showLabel: "=",
showChildren : '=', showChildren: "=",
unreadCount : '&', unreadCount: "&",
tag : '=' tag: "=",
}, },
restrict : 'E', restrict: "E",
replace : true, replace: true,
templateUrl : 'templates/_category.html', templateUrl: "templates/_category.html",
controller : ['$scope', '$state', 'FeedService', 'CategoryService', 'SettingsService', 'MobileService', controller: [
function($scope, $state, FeedService, CategoryService, SettingsService, MobileService) { "$scope",
$scope.settingsService = SettingsService; "$state",
"FeedService",
"CategoryService",
"SettingsService",
"MobileService",
function ($scope, $state, FeedService, CategoryService, SettingsService, MobileService) {
$scope.settingsService = SettingsService
$scope.getClass = function(level) { $scope.getClass = function (level) {
if ($scope.showLabel) { if ($scope.showLabel) {
return 'indent' + level; return "indent" + level
}
} }
};
$scope.categoryLabel = function(category) { $scope.categoryLabel = function (category) {
return $scope.showLabel !== true ? $scope.showLabel : category.name; return $scope.showLabel !== true ? $scope.showLabel : category.name
}; }
$scope.categoryCountLabel = function(category) { $scope.categoryCountLabel = function (category) {
var count = $scope.unreadCount({ var count = $scope.unreadCount({
category : category category: category,
}); })
var label = ''; var label = ""
if (count > 0) { if (count > 0) {
label += count; label += count
}
return label
} }
return label;
};
$scope.feedCountLabel = function(feed) { $scope.feedCountLabel = function (feed) {
var label = ''; var label = ""
if (feed.unread > 0) { if (feed.unread > 0) {
label += feed.unread; label += feed.unread
}
return label
} }
return label;
};
$scope.feedClicked = function(id, event) { $scope.feedClicked = function (id, event) {
// Could be called by a middle click // Could be called by a middle click
if (!event || (!event.ctrlKey && event.which == 1)) { if (!event || (!event.ctrlKey && event.which == 1)) {
MobileService.toggleLeftMenu(); MobileService.toggleLeftMenu()
if ($scope.selectedType == 'feed' && id == $scope.selectedId) { if ($scope.selectedType == "feed" && id == $scope.selectedId) {
$scope.$emit('emitReload'); $scope.$emit("emitReload")
} else { } else {
$state.transitionTo('feeds.view', { $state.transitionTo("feeds.view", {
_type : 'feed', _type: "feed",
_id : id _id: id,
}); })
} }
if (event) { if (event) {
event.preventDefault(); event.preventDefault()
event.stopPropagation(); event.stopPropagation()
}
} }
} }
};
$scope.categoryClicked = function(id, isTag) { $scope.categoryClicked = function (id, isTag) {
MobileService.toggleLeftMenu(); MobileService.toggleLeftMenu()
var type = isTag ? 'tag' : 'category'; var type = isTag ? "tag" : "category"
if ($scope.selectedType == type && id == $scope.selectedId) { if ($scope.selectedType == type && id == $scope.selectedId) {
$scope.$emit('emitReload'); $scope.$emit("emitReload")
} else { } else {
$state.transitionTo('feeds.view', { $state.transitionTo("feeds.view", {
_type : type, _type: type,
_id : id _id: id,
}); })
}
} }
};
$scope.showFeedDetails = function(feed) { $scope.showFeedDetails = function (feed) {
$state.transitionTo('feeds.feed_details', { $state.transitionTo("feeds.feed_details", {
_id : feed.id _id: feed.id,
}); })
}; }
$scope.showCategoryDetails = function(id, isTag) { $scope.showCategoryDetails = function (id, isTag) {
if (isTag) { if (isTag) {
$state.transitionTo('feeds.tag_details', { $state.transitionTo("feeds.tag_details", {
_id : id _id: id,
}); })
} else { } else {
$state.transitionTo('feeds.category_details', { $state.transitionTo("feeds.category_details", {
_id : id _id: id,
}); })
}
} }
};
$scope.toggleCategory = function(category, event) { $scope.toggleCategory = function (category, event) {
event.preventDefault(); event.preventDefault()
event.stopPropagation(); event.stopPropagation()
category.expanded = !category.expanded; category.expanded = !category.expanded
if (category.id == 'all') { if (category.id == "all") {
return; return
} }
CategoryService.collapse({ CategoryService.collapse({
id : category.id, id: category.id,
collapse : !category.expanded collapse: !category.expanded,
}); })
};
}]
};
}]);
module.directive('draggable', function() {
return {
restrict : 'A',
link : function(scope, element, attrs) {
element.draggable({
revert : 'invalid',
helper : 'clone',
distance : 10,
axis : 'y'
}).data('source', scope.$eval(attrs.draggable));
} }
};
});
module.directive('droppable', ['CategoryService', 'FeedService', function(CategoryService, FeedService) {
return {
restrict : 'A',
link : function(scope, element, attrs) {
element.droppable({
tolerance : 'pointer',
over : function(event, ui) {
}, },
drop : function(event, ui) { ],
var draggable = angular.element(ui.draggable); }
},
])
var source = draggable.data('source'); module.directive("draggable", function () {
var target = scope.$eval(attrs.droppable); return {
restrict: "A",
link: function (scope, element, attrs) {
element
.draggable({
revert: "invalid",
helper: "clone",
distance: 10,
axis: "y",
})
.data("source", scope.$eval(attrs.draggable))
},
}
})
module.directive("droppable", [
"CategoryService",
"FeedService",
function (CategoryService, FeedService) {
return {
restrict: "A",
link: function (scope, element, attrs) {
element.droppable({
tolerance: "pointer",
over: function (event, ui) {},
drop: function (event, ui) {
var draggable = angular.element(ui.draggable)
var source = draggable.data("source")
var target = scope.$eval(attrs.droppable)
if (angular.equals(source, target)) { if (angular.equals(source, target)) {
return; return
} }
var data = { var data = {
id : source.id, id: source.id,
name : source.name, name: source.name,
filter : source.filter filter: source.filter,
}; }
if (source.children) { if (source.children) {
// source is a category // source is a category
} else { } else {
// source is a feed // source is a feed
if (target.children) { if (target.children) {
// target is a category // target is a category
data.categoryId = target.id; data.categoryId = target.id
data.position = 0; data.position = 0
} else { } else {
// target is a feed // target is a feed
data.categoryId = target.categoryId; data.categoryId = target.categoryId
data.position = target.position; data.position = target.position
} }
FeedService.modify(data, function() { FeedService.modify(data, function () {
CategoryService.init(); CategoryService.init()
}); })
} }
scope.$apply(); scope.$apply()
}
});
}
};
}]);
module.directive('metricMeter', function() {
return {
scope : {
metric : '=',
label : '='
}, },
restrict : 'E', })
templateUrl : 'templates/_metrics.meter.html'
};
});
module.directive('metricGauge', function() {
return {
scope : {
metric : '=',
label : '='
}, },
restrict : 'E', }
templateUrl : 'templates/_metrics.gauge.html'
};
});
module.directive('metricTimer', function() {
return {
scope : {
metric : '=',
label : '='
}, },
restrict : 'E', ])
templateUrl : 'templates/_metrics.timer.html'
}; module.directive("metricMeter", function () {
}); return {
scope: {
metric: "=",
label: "=",
},
restrict: "E",
templateUrl: "templates/_metrics.meter.html",
}
})
module.directive("metricGauge", function () {
return {
scope: {
metric: "=",
label: "=",
},
restrict: "E",
templateUrl: "templates/_metrics.gauge.html",
}
})
module.directive("metricTimer", function () {
return {
scope: {
metric: "=",
label: "=",
},
restrict: "E",
templateUrl: "templates/_metrics.timer.html",
}
})

View File

@@ -1,113 +1,119 @@
var module = angular.module('commafeed.filters', []); var module = angular.module("commafeed.filters", [])
/** /**
* smart date formatter * smart date formatter
*/ */
module.filter('entryDate', function() { module.filter("entryDate", function () {
return function(timestamp, defaultValue) { return function (timestamp, defaultValue) {
if (!timestamp) { if (!timestamp) {
return defaultValue; return defaultValue
} }
var d = moment(timestamp); var d = moment(timestamp)
var now = moment(); var now = moment()
var formatted; var formatted
if (Math.abs(d.diff(now)) < 86400000) { if (Math.abs(d.diff(now)) < 86400000) {
formatted = d.fromNow(); formatted = d.fromNow()
} else { } else {
formatted = d.format('YYYY-MM-DD HH:mm'); formatted = d.format("YYYY-MM-DD HH:mm")
} }
return formatted; return formatted
}; }
}); })
/** /**
* rewrites iframes to use https if commafeed uses https * rewrites iframes to use https if commafeed uses https
*/ */
module.filter('iframeHttpsRewrite', function() { module.filter("iframeHttpsRewrite", function () {
return function(html) { return function (html) {
var result = html; var result = html
if (location.protocol === 'https:') { if (location.protocol === "https:") {
var wrapper = $('<div></div>').html(html); var wrapper = $("<div></div>").html(html)
$('iframe', wrapper).each(function(i, elem) { $("iframe", wrapper).each(function (i, elem) {
var e = $(elem); var e = $(elem)
e.attr('src', e.attr('src').replace(/^http:\/\//i, 'https://')); e.attr("src", e.attr("src").replace(/^http:\/\//i, "https://"))
}); })
result = wrapper.html(); result = wrapper.html()
} }
return result; return result
}; }
}); })
/** /**
* inserts title or alt-text after images, if any * inserts title or alt-text after images, if any
*/ */
module.filter('appendImageTitles', function() { module.filter("appendImageTitles", function () {
return function(html) { return function (html) {
var result = html; var result = html
var wrapper = $('<div></div>').html(html); var wrapper = $("<div></div>").html(html)
$('img', wrapper).each(function(i, elem) { $("img", wrapper).each(function (i, elem) {
var e = $(elem); var e = $(elem)
var title = e.attr('title') || e.attr('alt'); var title = e.attr("title") || e.attr("alt")
if (title) { if (title) {
var text = $('<span style="font-style: italic;"></span>').text(title); var text = $('<span style="font-style: italic;"></span>').text(title)
e.after(text); e.after(text)
} }
}); })
result = wrapper.html(); result = wrapper.html()
return result; return result
}; }
}); })
/** /**
* escapes the url * escapes the url
*/ */
module.filter('escape', function() { module.filter("escape", function () {
return encodeURIComponent; return encodeURIComponent
}); })
/** /**
* returns a trusted html content * returns a trusted html content
*/ */
module.filter('trustHtml', ['$sce', function($sce) { module.filter("trustHtml", [
return function(val) { "$sce",
return $sce.trustAsHtml(val); function ($sce) {
}; return function (val) {
}]); return $sce.trustAsHtml(val)
}
},
])
/** /**
* returns a trusted url * returns a trusted url
*/ */
module.filter('trustUrl', ['$sce', function($sce) { module.filter("trustUrl", [
return function(val) { "$sce",
return $sce.trustAsResourceUrl(val); function ($sce) {
}; return function (val) {
}]); return $sce.trustAsResourceUrl(val)
}
},
])
/** /**
* add the 'highlight-search' class to text matching keywords * add the 'highlight-search' class to text matching keywords
*/ */
module.filter('highlight', function() { module.filter("highlight", function () {
return function(html, keywords) { return function (html, keywords) {
if (keywords) { if (keywords) {
var handleKeyword = function(token, html) { var handleKeyword = function (token, html) {
var expr = new RegExp(token, 'gi'); var expr = new RegExp(token, "gi")
var container = $('<span>').html(html); var container = $("<span>").html(html)
var elements = container.find('*').addBack(); var elements = container.find("*").addBack()
var textNodes = elements.not('iframe').contents().not(elements); var textNodes = elements.not("iframe").contents().not(elements)
textNodes.each(function() { textNodes.each(function () {
var replaced = this.nodeValue.replace(expr, '<span class="highlight-search">$&</span>'); var replaced = this.nodeValue.replace(expr, '<span class="highlight-search">$&</span>')
$('<span>').html(replaced).insertBefore(this); $("<span>").html(replaced).insertBefore(this)
$(this).remove(); $(this).remove()
}); })
return container.html(); return container.html()
}; }
var tokens = keywords.split(' '); var tokens = keywords.split(" ")
for (var i = 0; i < tokens.length; i++) { for (var i = 0; i < tokens.length; i++) {
html = handleKeyword(tokens[i], html); html = handleKeyword(tokens[i], html)
} }
} }
return html; return html
}; }
}); })

View File

@@ -1,35 +1,37 @@
var module = angular.module('commafeed.i18n', []); var module = angular.module("commafeed.i18n", [])
module.service('LangService', [function() { module.service("LangService", [
function () {
this.langs = { this.langs = {
'ar': 'العربية', ar: "العربية",
'ca': 'Català', ca: "Català",
'en': 'English', en: "English",
'es': 'Español', es: "Español",
'de': 'Deutsch', de: "Deutsch",
'fa': 'فارسی', fa: "فارسی",
'fr': 'Français', fr: "Français",
'gl': 'Galician', gl: "Galician",
'glk': 'گیلکی', glk: "گیلکی",
'hu': 'Magyar', hu: "Magyar",
'id': 'Indonesian', id: "Indonesian",
'ja': '日本語', ja: "日本語",
'ko': '한국어', ko: "한국어",
'nl': 'Nederlands', nl: "Nederlands",
'nb': 'Norsk (bokmål)', nb: "Norsk (bokmål)",
'nn': 'Norsk (nynorsk)', nn: "Norsk (nynorsk)",
'pt': 'Português', pt: "Português",
'pl': 'Polski', pl: "Polski",
'ru': 'Русский', ru: "Русский",
'fi': 'Suomi', fi: "Suomi",
'sv': 'Svenska', sv: "Svenska",
'zh': '简体中文', zh: "简体中文",
'it': 'Italiano', it: "Italiano",
'tr': 'Türkçe', tr: "Türkçe",
'cy': 'Cymraeg', cy: "Cymraeg",
'sk': 'Slovenčina', sk: "Slovenčina",
'da': 'Danish', da: "Danish",
'cs': 'Čeština', cs: "Čeština",
'ms': 'Bahasa Malaysian' ms: "Bahasa Malaysian",
} }
}]); },
])

View File

@@ -1,145 +1,172 @@
var app = angular.module('commafeed', ['ngRoute', 'ngTouch', 'ngAnimate', 'ui.utils', 'ui.bootstrap', 'ui.router', 'ui.select2', var app = angular.module("commafeed", [
'commafeed.directives', 'commafeed.controllers', 'commafeed.services', 'commafeed.filters', 'commafeed.i18n', 'ngSanitize', "ngRoute",
'infinite-scroll', 'ngGrid', 'chieffancypants.loadingBar', 'pascalprecht.translate']); "ngTouch",
"ngAnimate",
"ui.utils",
"ui.bootstrap",
"ui.router",
"ui.select2",
"commafeed.directives",
"commafeed.controllers",
"commafeed.services",
"commafeed.filters",
"commafeed.i18n",
"ngSanitize",
"infinite-scroll",
"ngGrid",
"chieffancypants.loadingBar",
"pascalprecht.translate",
])
app.config([ app.config([
'$routeProvider', "$routeProvider",
'$stateProvider', "$stateProvider",
'$urlRouterProvider', "$urlRouterProvider",
'$httpProvider', "$httpProvider",
'$compileProvider', "$compileProvider",
'cfpLoadingBarProvider', "cfpLoadingBarProvider",
'$translateProvider', "$translateProvider",
function($routeProvider, $stateProvider, $urlRouterProvider, $httpProvider, $compileProvider, cfpLoadingBarProvider, function (
$translateProvider) { $routeProvider,
$stateProvider,
$urlRouterProvider,
$httpProvider,
$compileProvider,
cfpLoadingBarProvider,
$translateProvider
) {
$translateProvider.useStaticFilesLoader({ $translateProvider.useStaticFilesLoader({
prefix : 'i18n/', prefix: "i18n/",
suffix : '.js' suffix: ".js",
}); })
$translateProvider.preferredLanguage('en'); $translateProvider.preferredLanguage("en")
cfpLoadingBarProvider.includeSpinner = false; cfpLoadingBarProvider.includeSpinner = false
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|javascript):/); $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|javascript):/)
var interceptor = ['$rootScope', '$q', '$injector', function(scope, $q, $injector) { var interceptor = [
var f = {}; "$rootScope",
"$q",
"$injector",
function (scope, $q, $injector) {
var f = {}
f.response = function(response) { f.response = function (response) {
return response; return response
};
f.responseError = function(response) {
var status = response.status;
if (status == 401) {
$injector.get('$state').transitionTo('welcome');
} }
return $q.reject(response);
};
return f;
}];
$httpProvider.interceptors.push(interceptor); f.responseError = function (response) {
var status = response.status
if (status == 401) {
$injector.get("$state").transitionTo("welcome")
}
return $q.reject(response)
}
return f
},
]
$stateProvider.state('feeds', { $httpProvider.interceptors.push(interceptor)
'abstract' : true,
url : '/feeds',
templateUrl : 'templates/feeds.html'
});
$stateProvider.state('feeds.view', {
url : '/view/:_type/:_id',
templateUrl : 'templates/feeds.view.html',
controller : 'FeedListCtrl'
});
$stateProvider.state('feeds.subscribe', {
url : '/subscribe',
templateUrl : 'templates/feeds.subscribe.html',
controller : 'SubscribeCtrl'
});
$stateProvider.state('feeds.new_category', {
url : '/add_category',
templateUrl : 'templates/feeds.new_category.html',
controller : 'NewCategoryCtrl'
});
$stateProvider.state('feeds.import', {
url : '/import',
templateUrl : 'templates/feeds.import.html',
controller : 'ImportCtrl'
});
$stateProvider.state('feeds.search', {
url : '/search/:_keywords',
templateUrl : 'templates/feeds.view.html',
controller : 'FeedListCtrl'
});
$stateProvider.state('feeds.feed_details', {
url : '/details/feed/:_id',
templateUrl : 'templates/feeds.feed_details.html',
controller : 'FeedDetailsCtrl'
});
$stateProvider.state('feeds.category_details', {
url : '/details/category/:_id',
templateUrl : 'templates/feeds.category_details.html',
controller : 'CategoryDetailsCtrl'
});
$stateProvider.state('feeds.tag_details', {
url : '/details/tag/:_id',
templateUrl : 'templates/feeds.tag_details.html',
controller : 'TagDetailsCtrl'
});
$stateProvider.state('feeds.help', {
url : '/help',
templateUrl : 'templates/feeds.help.html',
controller : 'HelpController'
});
$stateProvider.state('feeds.settings', {
url : '/settings',
templateUrl : 'templates/settings.html',
controller : 'SettingsCtrl'
});
$stateProvider.state('feeds.profile', {
url : '/profile',
templateUrl : 'templates/profile.html',
controller : 'ProfileCtrl'
});
$stateProvider.state('admin', { $stateProvider.state("feeds", {
'abstract' : true, abstract: true,
url : '/admin', url: "/feeds",
templateUrl : 'templates/admin.html' templateUrl: "templates/feeds.html",
}); })
$stateProvider.state('admin.userlist', { $stateProvider.state("feeds.view", {
url : '/user/list', url: "/view/:_type/:_id",
templateUrl : 'templates/admin.userlist.html', templateUrl: "templates/feeds.view.html",
controller : 'ManageUsersCtrl' controller: "FeedListCtrl",
}); })
$stateProvider.state('admin.useradd', { $stateProvider.state("feeds.subscribe", {
url : '/user/add', url: "/subscribe",
templateUrl : 'templates/admin.useradd.html', templateUrl: "templates/feeds.subscribe.html",
controller : 'ManageUserCtrl' controller: "SubscribeCtrl",
}); })
$stateProvider.state('admin.useredit', { $stateProvider.state("feeds.new_category", {
url : '/user/edit/:_id', url: "/add_category",
templateUrl : 'templates/admin.useredit.html', templateUrl: "templates/feeds.new_category.html",
controller : 'ManageUserCtrl' controller: "NewCategoryCtrl",
}); })
$stateProvider.state('admin.settings', { $stateProvider.state("feeds.import", {
url : '/settings', url: "/import",
templateUrl : 'templates/admin.settings.html', templateUrl: "templates/feeds.import.html",
controller : 'ManageSettingsCtrl' controller: "ImportCtrl",
}); })
$stateProvider.state('admin.metrics', { $stateProvider.state("feeds.search", {
url : '/metrics', url: "/search/:_keywords",
templateUrl : 'templates/admin.metrics.html', templateUrl: "templates/feeds.view.html",
controller : 'MetricsCtrl' controller: "FeedListCtrl",
}); })
$stateProvider.state("feeds.feed_details", {
url: "/details/feed/:_id",
templateUrl: "templates/feeds.feed_details.html",
controller: "FeedDetailsCtrl",
})
$stateProvider.state("feeds.category_details", {
url: "/details/category/:_id",
templateUrl: "templates/feeds.category_details.html",
controller: "CategoryDetailsCtrl",
})
$stateProvider.state("feeds.tag_details", {
url: "/details/tag/:_id",
templateUrl: "templates/feeds.tag_details.html",
controller: "TagDetailsCtrl",
})
$stateProvider.state("feeds.help", {
url: "/help",
templateUrl: "templates/feeds.help.html",
controller: "HelpController",
})
$stateProvider.state("feeds.settings", {
url: "/settings",
templateUrl: "templates/settings.html",
controller: "SettingsCtrl",
})
$stateProvider.state("feeds.profile", {
url: "/profile",
templateUrl: "templates/profile.html",
controller: "ProfileCtrl",
})
$stateProvider.state('welcome', { $stateProvider.state("admin", {
url : '/welcome', abstract: true,
templateUrl : 'templates/welcome.html' url: "/admin",
}); templateUrl: "templates/admin.html",
})
$stateProvider.state("admin.userlist", {
url: "/user/list",
templateUrl: "templates/admin.userlist.html",
controller: "ManageUsersCtrl",
})
$stateProvider.state("admin.useradd", {
url: "/user/add",
templateUrl: "templates/admin.useradd.html",
controller: "ManageUserCtrl",
})
$stateProvider.state("admin.useredit", {
url: "/user/edit/:_id",
templateUrl: "templates/admin.useredit.html",
controller: "ManageUserCtrl",
})
$stateProvider.state("admin.settings", {
url: "/settings",
templateUrl: "templates/admin.settings.html",
controller: "ManageSettingsCtrl",
})
$stateProvider.state("admin.metrics", {
url: "/metrics",
templateUrl: "templates/admin.metrics.html",
controller: "MetricsCtrl",
})
$urlRouterProvider.when('/', '/feeds/view/category/all'); $stateProvider.state("welcome", {
$urlRouterProvider.when('/admin', '/admin/settings'); url: "/welcome",
$urlRouterProvider.otherwise('/'); templateUrl: "templates/welcome.html",
})
}]); $urlRouterProvider.when("/", "/feeds/view/category/all")
$urlRouterProvider.when("/admin", "/admin/settings")
$urlRouterProvider.otherwise("/")
},
])

View File

@@ -1,336 +1,375 @@
var module = angular.module('commafeed.services', ['ngResource']); var module = angular.module("commafeed.services", ["ngResource"])
module.service('AnalyticsService', ['$state', function($state) { module.service("AnalyticsService", [
this.track = function(path) { "$state",
if (typeof ga === 'undefined') { function ($state) {
return; this.track = function (path) {
if (typeof ga === "undefined") {
return
} }
path = path || $state.$current.url.prefix; path = path || $state.$current.url.prefix
ga('send', 'pageview', { ga("send", "pageview", {
page : path page: path,
}); })
}; }
}]); },
])
module.service('MobileService', ['$state', function($state) { module.service("MobileService", [
this.leftMenu = false; "$state",
this.rightMenu = false; function ($state) {
this.toggleLeftMenu = function() { this.leftMenu = false
this.leftMenu = !this.leftMenu; this.rightMenu = false
$('body').toggleClass('left-menu-active'); this.toggleLeftMenu = function () {
}; this.leftMenu = !this.leftMenu
this.toggleRightMenu = function() { $("body").toggleClass("left-menu-active")
this.rightMenu = !this.rightMenu; }
$('body').toggleClass('right-menu-active'); this.toggleRightMenu = function () {
}; this.rightMenu = !this.rightMenu
this.mobile = device.mobile() || device.tablet(); $("body").toggleClass("right-menu-active")
}]); }
this.mobile = device.mobile() || device.tablet()
},
])
module.factory('ProfileService', ['$resource', function($resource) { module.factory("ProfileService", [
var res = $resource('rest/user/profile/'); "$resource",
res.deleteAccount = $resource('rest/user/profile/deleteAccount').save; function ($resource) {
return res; var res = $resource("rest/user/profile/")
}]); res.deleteAccount = $resource("rest/user/profile/deleteAccount").save
return res
},
])
module.factory('SessionService', ['$resource', function($resource) { module.factory("SessionService", [
var res = {}; "$resource",
res.login = $resource('rest/user/login').save; function ($resource) {
res.register = $resource('rest/user/register').save; var res = {}
res.passwordReset = $resource('rest/user/passwordReset').save; res.login = $resource("rest/user/login").save
return res; res.register = $resource("rest/user/register").save
}]); res.passwordReset = $resource("rest/user/passwordReset").save
return res
},
])
module.factory('SettingsService', ['$resource', '$translate', function($resource, $translate) { module.factory("SettingsService", [
var res = $resource('rest/user/settings'); "$resource",
"$translate",
function ($resource, $translate) {
var res = $resource("rest/user/settings")
var s = {}; var s = {}
s.settings = {}; s.settings = {}
s.save = function(callback) { s.save = function (callback) {
res.save(s.settings, function(data) { res.save(s.settings, function (data) {
if (callback) { if (callback) {
callback(data); callback(data)
} }
}); })
};
s.init = function(callback) {
res.get(function(data) {
s.settings = data;
var lang = s.settings.language || 'en';
$translate.use(lang);
if (lang === 'zh') {
lang = 'zh-cn';
} else if (lang === 'ms') {
lang = 'ms-my';
} }
moment.locale(lang, {}); s.init = function (callback) {
res.get(function (data) {
s.settings = data
var lang = s.settings.language || "en"
$translate.use(lang)
if (lang === "zh") {
lang = "zh-cn"
} else if (lang === "ms") {
lang = "ms-my"
}
moment.locale(lang, {})
if (callback) { if (callback) {
callback(data); callback(data)
} }
}); })
}; }
s.init(); s.init()
return s; return s
}]); },
])
module.factory('FeedService', ['$resource', '$http', function($resource, $http) { module.factory("FeedService", [
"$resource",
"$http",
function ($resource, $http) {
var actions = { var actions = {
entries : { entries: {
method : 'GET', method: "GET",
params : { params: {
_method : 'entries' _method: "entries",
}
}, },
fetch : {
method : 'POST',
params : {
_method : 'fetch'
}
}, },
mark : { fetch: {
method : 'POST', method: "POST",
params : { params: {
_method : 'mark' _method: "fetch",
}
}, },
refresh : {
method : 'POST',
params : {
_method : 'refresh'
}
}, },
refreshAll : { mark: {
method : 'GET', method: "POST",
params : { params: {
_method : 'refreshAll' _method: "mark",
}
}, },
subscribe : {
method : 'POST',
params : {
_method : 'subscribe'
}
}, },
unsubscribe : { refresh: {
method : 'POST', method: "POST",
params : { params: {
_method : 'unsubscribe' _method: "refresh",
} },
},
refreshAll: {
method: "GET",
params: {
_method: "refreshAll",
},
},
subscribe: {
method: "POST",
params: {
_method: "subscribe",
},
},
unsubscribe: {
method: "POST",
params: {
_method: "unsubscribe",
},
},
modify: {
method: "POST",
params: {
_method: "modify",
},
}, },
modify : {
method : 'POST',
params : {
_method : 'modify'
} }
} var res = $resource("rest/feed/:_method", {}, actions)
}; res.get = $resource("rest/feed/get/:id").get
var res = $resource('rest/feed/:_method', {}, actions); return res
res.get = $resource('rest/feed/get/:id').get; },
return res; ])
}]);
module.factory('CategoryService', ['$resource', '$http', function($resource, $http) { module.factory("CategoryService", [
"$resource",
var traverse = function(callback, category, parentName) { "$http",
callback(category, parentName); function ($resource, $http) {
var children = category.children; var traverse = function (callback, category, parentName) {
callback(category, parentName)
var children = category.children
if (children) { if (children) {
for (var c = 0; c < children.length; c++) { for (var c = 0; c < children.length; c++) {
traverse(callback, children[c], category.name); traverse(callback, children[c], category.name)
}
} }
} }
};
// flatten categories // flatten categories
var flatten = function(category) { var flatten = function (category) {
var array = []; var array = []
var callback = function(category, parentName) { var callback = function (category, parentName) {
var name = category.name; var name = category.name
if (parentName) { if (parentName) {
name += (' (in ' + parentName + ')'); name += " (in " + parentName + ")"
} }
array.push({ array.push({
id : category.id, id: category.id,
name : name, name: name,
orig : category orig: category,
}); })
}; }
traverse(callback, category); traverse(callback, category)
return array; return array
}; }
// flatten feeds // flatten feeds
var flatFeeds = function(category) { var flatFeeds = function (category) {
var subs = []; var subs = []
var callback = function(category) { var callback = function (category) {
subs.push.apply(subs, category.feeds); subs.push.apply(subs, category.feeds)
}; }
traverse(callback, category); traverse(callback, category)
return subs; return subs
}; }
// flatten everything // flatten everything
var flatAll = function(category, a) { var flatAll = function (category, a) {
a.push([category.id, 'category']); a.push([category.id, "category"])
_.each(category.children, function(child) { _.each(category.children, function (child) {
flatAll(child, a); flatAll(child, a)
}); })
_.each(category.feeds, function(feed) { _.each(category.feeds, function (feed) {
a.push([feed.id, 'feed']); a.push([feed.id, "feed"])
}); })
}; }
var actions = { var actions = {
get : { get: {
method : 'GET', method: "GET",
ignoreLoadingBar : true, ignoreLoadingBar: true,
params : { params: {
_method : 'get' _method: "get",
}
}, },
entries : {
method : 'GET',
params : {
_method : 'entries'
}
}, },
mark : { entries: {
method : 'POST', method: "GET",
params : { params: {
_method : 'mark' _method: "entries",
}
}, },
add : {
method : 'POST',
params : {
_method : 'add'
}
}, },
remove : { mark: {
method : 'POST', method: "POST",
params : { params: {
_method : 'delete' _method: "mark",
} },
},
add: {
method: "POST",
params: {
_method: "add",
},
},
remove: {
method: "POST",
params: {
_method: "delete",
},
},
modify: {
method: "POST",
params: {
_method: "modify",
},
},
collapse: {
method: "POST",
params: {
_method: "collapse",
}, },
modify : {
method : 'POST',
params : {
_method : 'modify'
}
}, },
collapse : {
method : 'POST',
params : {
_method : 'collapse'
} }
} var res = $resource("rest/category/:_method", {}, actions)
}; res.subscriptions = {}
var res = $resource('rest/category/:_method', {}, actions); res.flatCategories = {}
res.subscriptions = {}; res.feeds = []
res.flatCategories = {};
res.feeds = [];
res.init = function(callback) { res.init = function (callback) {
res.get(function(data) { res.get(function (data) {
res.subscriptions = data; res.subscriptions = data
res.flatCategories = flatten(data); res.flatCategories = flatten(data)
res.feeds = flatFeeds(data); res.feeds = flatFeeds(data)
res.flatAll = []; res.flatAll = []
flatAll(data, res.flatAll); flatAll(data, res.flatAll)
res.flatAll.splice(1, 0, ['starred', 'category']); res.flatAll.splice(1, 0, ["starred", "category"])
if (callback) if (callback) callback(data)
callback(data); })
}); }
}; res.refresh = function (success, error) {
res.refresh = function(success, error) { res.get(
res.get(function(data) { function (data) {
_.merge(res.subscriptions, data); _.merge(res.subscriptions, data)
if (success) if (success) success(data)
success(data); },
}, function(data) { function (data) {
if (error) if (error) error(data)
error(data); }
}); )
}; }
res.init(); res.init()
return res; return res
}]); },
])
module.factory('EntryService', ['$resource', '$http', function($resource, $http) { module.factory("EntryService", [
"$resource",
"$http",
function ($resource, $http) {
var actions = { var actions = {
search : { search: {
method : 'GET', method: "GET",
params : { params: {
_method : 'search' _method: "search",
}
}, },
mark : {
method : 'POST',
ignoreLoadingBar : true,
params : {
_method : 'mark'
}
}, },
markMultiple : { mark: {
method : 'POST', method: "POST",
params : { ignoreLoadingBar: true,
_method : 'markMultiple' params: {
} _method: "mark",
},
},
markMultiple: {
method: "POST",
params: {
_method: "markMultiple",
},
},
star: {
method: "POST",
params: {
_method: "star",
},
},
tag: {
method: "POST",
params: {
_method: "tag",
}, },
star : {
method : 'POST',
params : {
_method : 'star'
}
}, },
tag : {
method : 'POST',
params : {
_method : 'tag'
} }
var res = $resource("rest/entry/:_method", {}, actions)
res.tags = []
var initTags = function () {
$http.get("rest/entry/tags").success(function (data) {
res.tags = []
res.tags.push.apply(res.tags, data)
res.tags.sort()
})
} }
}; var oldTag = res.tag
var res = $resource('rest/entry/:_method', {}, actions); res.tag = function (data) {
res.tags = []; oldTag(data, function () {
var initTags = function() { initTags()
$http.get('rest/entry/tags').success(function(data) { })
res.tags = []; }
res.tags.push.apply(res.tags, data); initTags()
res.tags.sort(); return res
}); },
}; ])
var oldTag = res.tag;
res.tag = function(data) {
oldTag(data, function() {
initTags();
});
};
initTags();
return res;
}]);
module.factory('AdminUsersService', ['$resource', function($resource) { module.factory("AdminUsersService", [
var res = {}; "$resource",
res.get = $resource('rest/admin/user/get/:id').get; function ($resource) {
res.getAll = $resource('rest/admin/user/getAll').query; var res = {}
res.save = $resource('rest/admin/user/save').save; res.get = $resource("rest/admin/user/get/:id").get
res.remove = $resource('rest/admin/user/delete').save; res.getAll = $resource("rest/admin/user/getAll").query
return res; res.save = $resource("rest/admin/user/save").save
}]); res.remove = $resource("rest/admin/user/delete").save
return res
},
])
module.factory('AdminSettingsService', ['$resource', function($resource) { module.factory("AdminSettingsService", [
var res = $resource('rest/admin/settings/'); "$resource",
return res; function ($resource) {
}]); var res = $resource("rest/admin/settings/")
return res
},
])
module.factory('AdminMetricsService', ['$resource', function($resource) { module.factory("AdminMetricsService", [
var res = $resource('rest/admin/metrics/'); "$resource",
return res; function ($resource) {
}]); var res = $resource("rest/admin/metrics/")
return res
},
])
module.factory('ServerService', ['$resource', function($resource) { module.factory("ServerService", [
var res = $resource('rest/server/get'); "$resource",
return res; function ($resource) {
}]); var res = $resource("rest/server/get")
return res
},
])

View File

@@ -1,7 +1,7 @@
$(function() { $(function () {
var reg = $('#register-panel'); var reg = $("#register-panel")
if (!reg) { if (!reg) {
return; return
} }
$('#login-panel').height(reg.height()); $("#login-panel").height(reg.height())
}); })

View File

@@ -7,9 +7,15 @@
</div> </div>
<div class="category-link" ng-click="categoryClicked(node.id, node.isTag)" ng-dblclick="showCategoryDetails(node.id, node.isTag)"> <div class="category-link" ng-click="categoryClicked(node.id, node.isTag)" ng-dblclick="showCategoryDetails(node.id, node.isTag)">
<span class="fldr"> <span class="fldr">
<i ng-class="{'icon-caret-right': !node.expanded, 'icon-caret-down': node.expanded}" ng-click="toggleCategory(node, $event)" <i
ng-show="showChildren"></i> ng-class="{'icon-caret-right': !node.expanded, 'icon-caret-down': node.expanded}"
<i ng-class="{'icon-star' : node.id == 'starred', 'icon-inbox': node.id == 'all', 'icon-tag' : node.isTag}" ng-show="!showChildren"></i> ng-click="toggleCategory(node, $event)"
ng-show="showChildren"
></i>
<i
ng-class="{'icon-star' : node.id == 'starred', 'icon-inbox': node.id == 'all', 'icon-tag' : node.isTag}"
ng-show="!showChildren"
></i>
</span> </span>
<span ng-class="{selected: (node.id == selectedId && (node.isTag ? selectedType == 'tag' : selectedType == 'category'))}"> <span ng-class="{selected: (node.id == selectedId && (node.isTag ? selectedType == 'tag' : selectedType == 'category'))}">
<span ng-class="{unread: unreadCount({category:node})}" class="bidi-embed">{{categoryLabel(node)}}</span> <span ng-class="{unread: unreadCount({category:node})}" class="bidi-embed">{{categoryLabel(node)}}</span>
@@ -18,17 +24,39 @@
</div> </div>
</div> </div>
<ul ng-show="node.expanded && showChildren"> <ul ng-show="node.expanded && showChildren">
<recursive> <category ng-repeat="child in node.children" <recursive>
ng-show="settingsService.settings.showRead == true || unreadCount({category:node}) > 0" node="child" level="level + 1" <category
selected-type="selectedType" selected-id="selectedId" show-label="true" show-children="true" ng-repeat="child in node.children"
unread-count="unreadCount({category:category})"> </category> </recursive> ng-show="settingsService.settings.showRead == true || unreadCount({category:node}) > 0"
<li ng-repeat="feed in node.feeds" ng-class="getClass(level)" class="tree-item" draggable="feed" droppable="feed" node="child"
ng-show="settingsService.settings.showRead == true || feed.unread > 0"> level="level + 1"
selected-type="selectedType"
selected-id="selectedId"
show-label="true"
show-children="true"
unread-count="unreadCount({category:category})"
>
</category>
</recursive>
<li
ng-repeat="feed in node.feeds"
ng-class="getClass(level)"
class="tree-item"
draggable="feed"
droppable="feed"
ng-show="settingsService.settings.showRead == true || feed.unread > 0"
>
<div class="pull-right" ng-click="showFeedDetails(feed)"> <div class="pull-right" ng-click="showFeedDetails(feed)">
<i class="icon-wrench config pointer"></i> <i class="icon-wrench config pointer"></i>
</div> </div>
<a ng-click="feedClicked(feed.id, $event)" ng-dblclick="showFeedDetails(feed)" class="feed-link" href="{{feed.feedLink}}" target="_blank" <a
ng-class="{error: feed.message && feed.errorCount > 10, selected: (feed.id == selectedId && selectedType == 'feed') }"> ng-click="feedClicked(feed.id, $event)"
ng-dblclick="showFeedDetails(feed)"
class="feed-link"
href="{{feed.feedLink}}"
target="_blank"
ng-class="{error: feed.message && feed.errorCount > 10, selected: (feed.id == selectedId && selectedType == 'feed') }"
>
<favicon url="feed.iconUrl" /> <favicon url="feed.iconUrl" />
<span ng-class="{unread: feed.unread}" class="bidi-embed">{{feed.name}}</span> <span ng-class="{unread: feed.unread}" class="bidi-embed">{{feed.name}}</span>
<span class="unread-counter">{{feedCountLabel(feed)}}</span> <span class="unread-counter">{{feedCountLabel(feed)}}</span>

View File

@@ -5,9 +5,13 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" ng-click="close()">&times;</button> <button type="button" class="close" ng-click="close()">&times;</button>
<h4> <h4>
<input ng-model="filter" class="filter-input" <input
ui-keydown="{'up': 'focusPrevious($event)', 'down': 'focusNext($event)', 'enter': 'openFocused()' }" placeholder="{{'feedsearch.hint' | translate}}" ng-model="filter"
focus="feedSearchModal"> class="filter-input"
ui-keydown="{'up': 'focusPrevious($event)', 'down': 'focusNext($event)', 'enter': 'openFocused()' }"
placeholder="{{'feedsearch.hint' | translate}}"
focus="feedSearchModal"
/>
</h4> </h4>
<small>{{ 'feedsearch.help' | translate }}</small> <small>{{ 'feedsearch.help' | translate }}</small>
</div> </div>
@@ -15,7 +19,7 @@
<strong>{{ 'feedsearch.result_prefix' | translate }}</strong> <strong>{{ 'feedsearch.result_prefix' | translate }}</strong>
<span ng-repeat="feed in (filtered = (CategoryService.feeds | filter:{name: filter} | limitTo:40))"> <span ng-repeat="feed in (filtered = (CategoryService.feeds | filter:{name: filter} | limitTo:40))">
<span ng-class="{block: filter, focus: focus.id == feed.id}" class="feed-link"> <span ng-class="{block: filter, focus: focus.id == feed.id}" class="feed-link">
<a class=" pointer" ng-click="goToFeed(feed.id)"> <a class="pointer" ng-click="goToFeed(feed.id)">
<favicon url="feed.iconUrl" /> <favicon url="feed.iconUrl" />
&nbsp;{{feed.name}} &nbsp;{{feed.name}}
</a> </a>

View File

@@ -1,3 +1,3 @@
<div ng-controller="FooterController"> <div ng-controller="FooterController">
<iframe ng-if="subToMeUrl" style="display: none;" ng-src='{{subToMeUrl}}'></iframe> <iframe ng-if="subToMeUrl" style="display: none" ng-src="{{subToMeUrl}}"></iframe>
</div> </div>

View File

@@ -9,6 +9,5 @@
<dt>Total</dt> <dt>Total</dt>
<dd>{{metric.count}}</dd> <dd>{{metric.count}}</dd>
</dl> </dl>
</div> </div>

View File

@@ -12,6 +12,5 @@
<dt>min/max/mean (ms)</dt> <dt>min/max/mean (ms)</dt>
<dd>{{metric.min/1000000 | number:0}} {{metric.max/1000000 | number:0}} {{metric.mean/1000000 | number:0}}</dd> <dd>{{metric.min/1000000 | number:0}} {{metric.max/1000000 | number:0}} {{metric.mean/1000000 | number:0}}</dd>
</dl> </dl>
</div> </div>

View File

@@ -70,5 +70,4 @@
u u
</dt> </dt>
<dd>{{ 'about.shortcuts.feed_search' | translate }}</dd> <dd>{{ 'about.shortcuts.feed_search' | translate }}</dd>
</dl> </dl>

View File

@@ -60,26 +60,55 @@
<div class="actions btn-group" id="toolbar-read-mode"> <div class="actions btn-group" id="toolbar-read-mode">
<div ng-if="!MobileService.mobile || MobileService.rightMenu"> <div ng-if="!MobileService.mobile || MobileService.rightMenu">
<div class="btn-group read-mode"> <div class="btn-group read-mode">
<button type="button" class="btn btn-default" ng-click="settingsService.settings.readingMode = 'unread'" ng-class="{'active': settingsService.settings.readingMode == 'unread'}">{{ <button
'toolbar.unread' | translate }}</button> type="button"
<button type="button" class="btn btn-default" ng-click="settingsService.settings.readingMode = 'all'" ng-class="{'active': settingsService.settings.readingMode == 'all'}">{{ class="btn btn-default"
'toolbar.all' | translate }}</button> ng-click="settingsService.settings.readingMode = 'unread'"
ng-class="{'active': settingsService.settings.readingMode == 'unread'}"
>
{{ 'toolbar.unread' | translate }}
</button>
<button
type="button"
class="btn btn-default"
ng-click="settingsService.settings.readingMode = 'all'"
ng-class="{'active': settingsService.settings.readingMode == 'all'}"
>
{{ 'toolbar.all' | translate }}
</button>
</div> </div>
<div class="btn-group" id="toolbar-read-order"> <div class="btn-group" id="toolbar-read-order">
<a type="button" class="btn btn-default" ng-click="toggleOrder()" title="{{ 'toolbar.sort_by_asc_desc' | translate }}" <a
ng-class="{'active' : settingsService.settings.readingOrder == 'asc' || settingsService.settings.readingOrder == 'desc'}"> type="button"
<i ng-class="{'icon-arrow-up' : settingsService.settings.readingOrder == 'asc', 'icon-arrow-down': settingsService.settings.readingOrder != 'asc'}"></i> class="btn btn-default"
ng-click="toggleOrder()"
title="{{ 'toolbar.sort_by_asc_desc' | translate }}"
ng-class="{'active' : settingsService.settings.readingOrder == 'asc' || settingsService.settings.readingOrder == 'desc'}"
>
<i
ng-class="{'icon-arrow-up' : settingsService.settings.readingOrder == 'asc', 'icon-arrow-down': settingsService.settings.readingOrder != 'asc'}"
></i>
</a> </a>
</div> </div>
<div class="btn-group" id="toolbar-read-view-settings"> <div class="btn-group" id="toolbar-read-view-settings">
<a type="button" class="btn btn-default" ng-click="settingsService.settings.viewMode = 'title'" ng-class="{'active': settingsService.settings.viewMode == 'title'}" <a
title="{{ 'toolbar.titles_only' | translate }}"> type="button"
class="btn btn-default"
ng-click="settingsService.settings.viewMode = 'title'"
ng-class="{'active': settingsService.settings.viewMode == 'title'}"
title="{{ 'toolbar.titles_only' | translate }}"
>
<i class="icon-list"></i> <i class="icon-list"></i>
</a> </a>
<a type="button" class="btn btn-default" ng-click="settingsService.settings.viewMode = 'expanded'" ng-class="{'active': settingsService.settings.viewMode == 'expanded'}" <a
title="{{ 'toolbar.expanded_view' | translate }}"> type="button"
class="btn btn-default"
ng-click="settingsService.settings.viewMode = 'expanded'"
ng-class="{'active': settingsService.settings.viewMode == 'expanded'}"
title="{{ 'toolbar.expanded_view' | translate }}"
>
<i class="icon-th-list"></i> <i class="icon-th-list"></i>
</a> </a>
</div> </div>
@@ -115,7 +144,7 @@
</div> </div>
<div class="btn-group"> <div class="btn-group">
<form ng-submit="search()" class="input-group keywords" ng-if="!MobileService.mobile"> <form ng-submit="search()" class="input-group keywords" ng-if="!MobileService.mobile">
<input type="text" class="form-control" ng-model="keywords"></input> <input type="text" class="form-control" ng-model="keywords" />
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn btn-default" type="submit"> <button class="btn btn-default" type="submit">
<i class="icon-search"></i> <i class="icon-search"></i>
@@ -124,11 +153,15 @@
</form> </form>
</div> </div>
<div class="btn-group donate"> <div class="btn-group donate">
<button class="btn btn-success" type="button" ng-click="toHelp()" title="{{ 'toolbar.about' | translate }} / {{ 'toolbar.donate' | translate }}"> <button
class="btn btn-success"
type="button"
ng-click="toHelp()"
title="{{ 'toolbar.about' | translate }} / {{ 'toolbar.donate' | translate }}"
>
<i class="icon-info-sign"></i> <i class="icon-info-sign"></i>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<span ng-if="!MobileService.mobile" ng-bind-html="ServerService.announcement | trustHtml"></span> <span ng-if="!MobileService.mobile" ng-bind-html="ServerService.announcement | trustHtml"></span>

View File

@@ -1,5 +1,10 @@
<div ng-controller="CategoryTreeCtrl" class="sidebar-nav-fixed" mousewheel-scrolling ui-jq="resizable" <div
ui-options="{handles: 'e', resize: resizeCallback}"> ng-controller="CategoryTreeCtrl"
class="sidebar-nav-fixed"
mousewheel-scrolling
ui-jq="resizable"
ui-options="{handles: 'e', resize: resizeCallback}"
>
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-default" ui-sref="feeds.subscribe" ng-click="MobileService.toggleLeftMenu()"> <button class="btn btn-default" ui-sref="feeds.subscribe" ng-click="MobileService.toggleLeftMenu()">
<span class="icon-rss"></span> <span class="icon-rss"></span>
@@ -33,16 +38,48 @@
<div class="css-treeview"> <div class="css-treeview">
<ul> <ul>
<category node="CategoryService.subscriptions" show-label="'tree.all' | translate" show-children="false" level="0" selected-type="selectedType" <category
selected-id="selectedId" unread-count="unreadCount(category)"> </category> node="CategoryService.subscriptions"
<category node="starred" show-label="'tree.starred' | translate" show-children="false" level="0" selected-type="selectedType" show-label="'tree.all' | translate"
selected-id="selectedId" unread-count="unreadCount(category)"> </category> show-children="false"
<category node="CategoryService.subscriptions" show-label="false" show-children="true" level="0" selected-type="selectedType" level="0"
selected-id="selectedId" unread-count="unreadCount(category)"> </category> selected-type="selectedType"
selected-id="selectedId"
unread-count="unreadCount(category)"
>
</category>
<category
node="starred"
show-label="'tree.starred' | translate"
show-children="false"
level="0"
selected-type="selectedType"
selected-id="selectedId"
unread-count="unreadCount(category)"
>
</category>
<category
node="CategoryService.subscriptions"
show-label="false"
show-children="true"
level="0"
selected-type="selectedType"
selected-id="selectedId"
unread-count="unreadCount(category)"
>
</category>
<li ng-repeat="tag in tags | orderBy: 'name'"> <li ng-repeat="tag in tags | orderBy: 'name'">
<category node="tag" show-label="tag.name" show-children="false" level="0" selected-type="selectedType" selected-id="selectedId" <category
unread-count="unreadCount(category)"> </category> node="tag"
show-label="tag.name"
show-children="false"
level="0"
selected-type="selectedType"
selected-id="selectedId"
unread-count="unreadCount(category)"
>
</category>
</li> </li>
</ul> </ul>
</div> </div>

View File

@@ -1,28 +1,60 @@
<div> <div>
<div class="col-md-6"> <div class="col-md-6">
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedQueues.refill']" label="'Refresh queue refill rate (/sec)'"></metric-meter> <metric-meter
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshTaskGiver.feedRefreshed']" label="'Feed refreshed (/sec)'"></metric-meter> metric="metrics.meters['com.commafeed.backend.feed.FeedQueues.refill']"
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.feedUpdated']" label="'Feed updated (/sec)'"></metric-meter> label="'Refresh queue refill rate (/sec)'"
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheHit']" label="'Entry cache hit (/sec)'"></metric-meter> ></metric-meter>
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheMiss']" label="'Entry cache miss (/sec)'"></metric-meter> <metric-meter
metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshTaskGiver.feedRefreshed']"
label="'Feed refreshed (/sec)'"
></metric-meter>
<metric-meter
metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.feedUpdated']"
label="'Feed updated (/sec)'"
></metric-meter>
<metric-meter
metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheHit']"
label="'Entry cache hit (/sec)'"
></metric-meter>
<metric-meter
metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheMiss']"
label="'Entry cache miss (/sec)'"
></metric-meter>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.active']" <metric-gauge
label="'Feed Updater active'"></metric-gauge> metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.active']"
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.pending']" label="'Feed Updater active'"
label="'Feed Updater queued'"></metric-gauge> ></metric-gauge>
<metric-gauge
metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.pending']"
label="'Feed Updater queued'"
></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.active']" <metric-gauge
label="'Feed Worker active'"></metric-gauge> metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.active']"
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.pending']" label="'Feed Worker active'"
label="'Feed Worker queued'"></metric-gauge> ></metric-gauge>
<metric-gauge
metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.pending']"
label="'Feed Worker queued'"
></metric-gauge>
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.addQueue']" label="'Task Giver Add Queue'"></metric-gauge> <metric-gauge
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.takeQueue']" label="'Task Giver Take Queue'"></metric-gauge> metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.addQueue']"
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.giveBackQueue']" label="'Task Giver Give Back Queue'"></metric-gauge> label="'Task Giver Add Queue'"
></metric-gauge>
<metric-gauge
metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.takeQueue']"
label="'Task Giver Take Queue'"
></metric-gauge>
<metric-gauge
metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.giveBackQueue']"
label="'Task Giver Give Back Queue'"
></metric-gauge>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div ng-repeat="(name, timer) in metrics.timers"> <div ng-repeat="(name, timer) in metrics.timers">
<metric-timer metric="timer" label="name"></metric-gauge> <metric-timer metric="timer" label="name"></metric-timer>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -19,8 +19,14 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-3" for="publicUrl">Public URL</label> <label class="control-label col-sm-3" for="publicUrl">Public URL</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" id="publicUrl" name="publicUrl" class="form-control" placeholder="http://localhost:8082/commafeed" <input
ng-model="settings.publicUrl" /> type="text"
id="publicUrl"
name="publicUrl"
class="form-control"
placeholder="http://localhost:8082/commafeed"
ng-model="settings.publicUrl"
/>
<span class="help-block">The URL in your address bar right now, up to the # (not included)</span> <span class="help-block">The URL in your address bar right now, up to the # (not included)</span>
</div> </div>
</div> </div>
@@ -28,14 +34,24 @@
<label class="control-label col-sm-3" for="publicUrl">Allow registrations</label> <label class="control-label col-sm-3" for="publicUrl">Allow registrations</label>
<div class="col-sm-9"> <div class="col-sm-9">
<div class="checkbox"> <div class="checkbox">
<input type="checkbox" id="allowRegistrations" name="allowRegistrations" ng-model="settings.allowRegistrations" /> <input
type="checkbox"
id="allowRegistrations"
name="allowRegistrations"
ng-model="settings.allowRegistrations"
/>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-3" for="googleAnalyticsTrackingCode">Google Analytics tracking code</label> <label class="control-label col-sm-3" for="googleAnalyticsTrackingCode">Google Analytics tracking code</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="googleAnalyticsTrackingCode" class="form-control" ng-model="settings.googleAnalyticsTrackingCode" /> <input
type="text"
name="googleAnalyticsTrackingCode"
class="form-control"
ng-model="settings.googleAnalyticsTrackingCode"
/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -48,15 +64,19 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-3" for="databaseUpdateThreads">Database update threads</label> <label class="control-label col-sm-3" for="databaseUpdateThreads">Database update threads</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="number" name="databaseUpdateThreads" class="form-control" ng-model="settings.databaseUpdateThreads" /> <input
type="number"
name="databaseUpdateThreads"
class="form-control"
ng-model="settings.databaseUpdateThreads"
/>
<span class="help-inline">Requires restart</span> <span class="help-inline">Requires restart</span>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-3" for="announcement">Announcement</label> <label class="control-label col-sm-3" for="announcement">Announcement</label>
<div class="col-sm-9"> <div class="col-sm-9">
<textarea name="announcement" rows="10" class="form-control" ng-model="settings.announcement"> <textarea name="announcement" rows="10" class="form-control" ng-model="settings.announcement"> </textarea>
</textarea>
</div> </div>
</div> </div>
</div> </div>
@@ -134,7 +154,13 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-3" for="refreshIntervalMinutes">Refresh feeds every (minutes)</label> <label class="control-label col-sm-3" for="refreshIntervalMinutes">Refresh feeds every (minutes)</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="number" name="refreshIntervalMinutes" class="form-control" min="1" ng-model="settings.refreshIntervalMinutes" /> <input
type="number"
name="refreshIntervalMinutes"
class="form-control"
min="1"
ng-model="settings.refreshIntervalMinutes"
/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@@ -40,7 +40,14 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">Save</button> <button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn btn-danger" ng-click="remove()" confirm-click="'Are you sure you want to delete this user?'">Delete</button> <button
type="button"
class="btn btn-danger"
ng-click="remove()"
confirm-click="'Are you sure you want to delete this user?'"
>
Delete
</button>
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button> <button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
</div> </div>
</div> </div>

View File

@@ -6,7 +6,7 @@
<div class="form-group" ng-class="{error : !form.name.$valid}" ng-if="!isMeta()"> <div class="form-group" ng-class="{error : !form.name.$valid}" ng-if="!isMeta()">
<label class="col-sm-2 control-label">{{ 'details.name' | translate }}</label> <label class="col-sm-2 control-label">{{ 'details.name' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" name="name" ng-model="category.name" class="form-control" required></input> <input type="text" name="name" ng-model="category.name" class="form-control" required />
<span class="help-block" ng-show="!form.name.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!form.name.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>
@@ -14,9 +14,12 @@
<div class="form-group" ng-class="{error : !form.category.$valid}" ng-if="!isMeta()"> <div class="form-group" ng-class="{error : !form.category.$valid}" ng-if="!isMeta()">
<label class="col-sm-2 control-label">{{ 'details.parent_category' | translate }}</label> <label class="col-sm-2 control-label">{{ 'details.parent_category' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<select name="category" class="form-control" ng-model="category.parentId" <select
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories | filter: filterCurrent"> name="category"
</select> class="form-control"
ng-model="category.parentId"
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories | filter: filterCurrent"
></select>
<span class="help-block" ng-show="!form.category.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!form.category.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>
@@ -31,7 +34,12 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">{{ 'details.feed_url' | translate }}</label> <label class="col-sm-2 control-label">{{ 'details.feed_url' | translate }}</label>
<div class="col-sm-10 form-control-static"> <div class="col-sm-10 form-control-static">
<a ng-show="user.apiKey" href="{{'rest/category/entriesAsFeed?id=' + category.id + '&apiKey=' + user.apiKey}}" target="_blank">{{ 'global.link' | translate }}</a> <a
ng-show="user.apiKey"
href="{{'rest/category/entriesAsFeed?id=' + category.id + '&apiKey=' + user.apiKey}}"
target="_blank"
>{{ 'global.link' | translate }}</a
>
<span ng-show="!user.apiKey">{{ 'details.generate_api_key_first' | translate }}</span> <span ng-show="!user.apiKey">{{ 'details.generate_api_key_first' | translate }}</span>
</div> </div>
</div> </div>
@@ -39,11 +47,17 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary" ng-if="!isMeta()">{{ 'global.save' | translate }}</button> <button type="submit" class="btn btn-primary" ng-if="!isMeta()">{{ 'global.save' | translate }}</button>
<button type="button" class="btn btn-danger" ng-click="deleteCategory()" ng-show="!isMeta()" <button
confirm-click="'details.delete_category_confirmation' | translate">{{ 'global.delete' | translate }}</button> type="button"
class="btn btn-danger"
ng-click="deleteCategory()"
ng-show="!isMeta()"
confirm-click="'details.delete_category_confirmation' | translate"
>
{{ 'global.delete' | translate }}
</button>
<button type="button" class="btn btn-default" ng-click="back()">{{ 'global.cancel' | translate }}</button> <button type="button" class="btn btn-default" ng-click="back()">{{ 'global.cancel' | translate }}</button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>

View File

@@ -19,7 +19,7 @@
<div class="form-group" ng-class="{error : !form.name.$valid}"> <div class="form-group" ng-class="{error : !form.name.$valid}">
<label class="col-sm-2 control-label">{{ 'details.name' | translate }}</label> <label class="col-sm-2 control-label">{{ 'details.name' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" name="name" ng-model="sub.name" class="form-control" required></input> <input type="text" name="name" ng-model="sub.name" class="form-control" required />
<span class="help-block" ng-show="!form.name.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!form.name.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>
@@ -27,9 +27,12 @@
<div class="form-group" ng-class="{error : !form.category.$valid}"> <div class="form-group" ng-class="{error : !form.category.$valid}">
<label class="col-sm-2 control-label">{{ 'details.category' | translate }}</label> <label class="col-sm-2 control-label">{{ 'details.category' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<select name="category" class="form-control" ng-model="sub.categoryId" <select
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories"> name="category"
</select> class="form-control"
ng-model="sub.categoryId"
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories"
></select>
<span class="help-block" ng-show="!form.category.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!form.category.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>
@@ -65,7 +68,9 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">{{ 'details.feed_url' | translate }}</label> <label class="col-sm-2 control-label">{{ 'details.feed_url' | translate }}</label>
<div class="col-sm-10 form-control-static"> <div class="col-sm-10 form-control-static">
<a ng-show="user.apiKey" href="{{'rest/feed/entriesAsFeed?id=' + sub.id + '&apiKey=' + user.apiKey}}" target="_blank">{{ 'global.link' | translate }}</a> <a ng-show="user.apiKey" href="{{'rest/feed/entriesAsFeed?id=' + sub.id + '&apiKey=' + user.apiKey}}" target="_blank"
>{{ 'global.link' | translate }}</a
>
<span ng-show="!user.apiKey">{{ 'details.generate_api_key_first' | translate }}</span> <span ng-show="!user.apiKey">{{ 'details.generate_api_key_first' | translate }}</span>
</div> </div>
</div> </div>
@@ -73,7 +78,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">{{ 'details.filtering_expression' | translate }}</label> <label class="col-sm-2 control-label">{{ 'details.filtering_expression' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" name="filter" ng-model="sub.filter" class="form-control"></input> <input type="text" name="filter" ng-model="sub.filter" class="form-control" />
<p class="help-block pre-wrap" ng-bind-html="'details.filtering_expression_help' | translate"></p> <p class="help-block pre-wrap" ng-bind-html="'details.filtering_expression_help' | translate"></p>
</div> </div>
</div> </div>
@@ -81,10 +86,16 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">{{ 'global.save' | translate }}</button> <button type="submit" class="btn btn-primary">{{ 'global.save' | translate }}</button>
<button type="button" class="btn btn-danger" ng-click="unsubscribe()" confirm-click="'details.unsubscribe_confirmation' | translate">{{ 'details.unsubscribe' | translate }}</button> <button
type="button"
class="btn btn-danger"
ng-click="unsubscribe()"
confirm-click="'details.unsubscribe_confirmation' | translate"
>
{{ 'details.unsubscribe' | translate }}
</button>
<button type="button" class="btn btn-default" ng-click="back()">{{ 'global.cancel' | translate }}</button> <button type="button" class="btn btn-default" ng-click="back()">{{ 'global.cancel' | translate }}</button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>

View File

@@ -1,6 +1,5 @@
<div class="row help"> <div class="row help">
<div class="col-md-6"> <div class="col-md-6">
<div class="about-module"> <div class="about-module">
<h4> <h4>
<i class="icon-question-sign"></i> <i class="icon-question-sign"></i>
@@ -26,14 +25,20 @@
</h4> </h4>
<p>{{ 'about.line3' | translate }}</p> <p>{{ 'about.line3' | translate }}</p>
<form class="donate-action" action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top"> <form class="donate-action" action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_donations"> <input type="hidden" name="cmd" value="_donations" />
<input type="hidden" name="business" value="9CNQHMJG2ZJVY"> <input type="hidden" name="business" value="9CNQHMJG2ZJVY" />
<input type="hidden" name="lc" value="US"> <input type="hidden" name="lc" value="US" />
<input type="hidden" name="item_name" value="CommaFeed"> <input type="hidden" name="item_name" value="CommaFeed" />
<input type="hidden" name="bn" value="PP-DonationsBF:btn_donateCC_LG.gif:NonHosted"> <input type="hidden" name="bn" value="PP-DonationsBF:btn_donateCC_LG.gif:NonHosted" />
<input type="image" class="donate-image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" <input
alt="PayPal - The safer, easier way to pay online!"> type="image"
<input type="hidden" name="currency_code" value="USD"> class="donate-image"
src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif"
border="0"
name="submit"
alt="PayPal - The safer, easier way to pay online!"
/>
<input type="hidden" name="currency_code" value="USD" />
<select name="currency_code"> <select name="currency_code">
<option value="EUR">Euro</option> <option value="EUR">Euro</option>
<option value="USD">US Dollars</option> <option value="USD">US Dollars</option>
@@ -57,13 +62,19 @@
<a href="https://play.google.com/store/apps/details?id=com.mv.cloudfeedlr" target="_blank">Cloudfeedlr</a> <a href="https://play.google.com/store/apps/details?id=com.mv.cloudfeedlr" target="_blank">Cloudfeedlr</a>
</p> </p>
<p> <p>
<a href="https://chrome.google.com/webstore/detail/commafeed/bpbfpjiciblcfeganojjkfapnllbhdga" target="_blank">{{ 'about.goodies.chrome_extension' | translate }}</a> <a href="https://chrome.google.com/webstore/detail/commafeed/bpbfpjiciblcfeganojjkfapnllbhdga" target="_blank"
>{{ 'about.goodies.chrome_extension' | translate }}</a
>
</p> </p>
<p> <p>
<a href="https://addons.mozilla.org/en-US/firefox/addon/commafeed/" target="_blank">{{ 'about.goodies.firefox_extension' | translate }}</a> <a href="https://addons.mozilla.org/en-US/firefox/addon/commafeed/" target="_blank"
>{{ 'about.goodies.firefox_extension' | translate }}</a
>
</p> </p>
<p> <p>
<a href="https://addons.opera.com/en/extensions/details/commafeed-extension-for-opera/" target="_blank">{{ 'about.goodies.opera_extension' | translate }}</a> <a href="https://addons.opera.com/en/extensions/details/commafeed-extension-for-opera/" target="_blank"
>{{ 'about.goodies.opera_extension' | translate }}</a
>
</p> </p>
<p> <p>
@@ -79,14 +90,20 @@
<br /> <br />
<br /> <br />
{{ 'subscribe.category' | translate }} {{ 'subscribe.category' | translate }}
<select ng-model="categoryId" ng-options="cat.id as cat.name for cat in CategoryService.flatCategories" class="bookmarklet-select"> <select
</select> ng-model="categoryId"
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories"
class="bookmarklet-select"
></select>
<select ng-model="order" class="bookmarklet-select"> <select ng-model="order" class="bookmarklet-select">
<option value="desc">{{ 'about.goodies.subscribe_bookmarklet_desc' | translate }}</option> <option value="desc">{{ 'about.goodies.subscribe_bookmarklet_desc' | translate }}</option>
<option value="asc">{{ 'about.goodies.subscribe_bookmarklet_asc' | translate }}</option> <option value="asc">{{ 'about.goodies.subscribe_bookmarklet_asc' | translate }}</option>
</select> </select>
<a href="javascript:window.location.href='{{baseUrl}}next?category={{categoryId}}&order={{order}}&t='+new Date().getTime();" <a
target="_blank">{{ 'global.link' | translate }}</a> href="javascript:window.location.href='{{baseUrl}}next?category={{categoryId}}&order={{order}}&t='+new Date().getTime();"
target="_blank"
>{{ 'global.link' | translate }}</a
>
</p> </p>
</div> </div>
@@ -97,7 +114,9 @@
</h4> </h4>
<p>{{ 'about.translation.message' | translate }}</p> <p>{{ 'about.translation.message' | translate }}</p>
<p> <p>
<a href="https://github.com/Athou/commafeed#translate-commafeed-into-your-language" target="_blank"> {{ 'about.translation.link' | translate }} </a> <a href="https://github.com/Athou/commafeed#translate-commafeed-into-your-language" target="_blank">
{{ 'about.translation.link' | translate }}
</a>
</p> </p>
</div> </div>
<div class="about-module"> <div class="about-module">
@@ -127,18 +146,18 @@
</h4> </h4>
<a class="twitter-timeline" href="https://twitter.com/CommaFeed" data-widget-id="333897786657480704">Tweets by @CommaFeed</a> <a class="twitter-timeline" href="https://twitter.com/CommaFeed" data-widget-id="333897786657480704">Tweets by @CommaFeed</a>
<script> <script>
!function(d, s, id) { !(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0], p = /^http:/.test(d.location) ? 'http' : 'https'; var js,
fjs = d.getElementsByTagName(s)[0],
p = /^http:/.test(d.location) ? "http" : "https"
if (!d.getElementById(id)) { if (!d.getElementById(id)) {
js = d.createElement(s); js = d.createElement(s)
js.id = id; js.id = id
js.src = p + "://platform.twitter.com/widgets.js"; js.src = p + "://platform.twitter.com/widgets.js"
fjs.parentNode.insertBefore(js, fjs); fjs.parentNode.insertBefore(js, fjs)
} }
}(document, "script", "twitter-wjs"); })(document, "script", "twitter-wjs")
</script> </script>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -5,8 +5,8 @@
<form class="form-horizontal" action="rest/feed/import" method="post" enctype="multipart/form-data"> <form class="form-horizontal" action="rest/feed/import" method="post" enctype="multipart/form-data">
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label">{{ 'import.xml_file' | translate }}</label> <label class="col-sm-2 control-label">{{ 'import.xml_file' | translate }}</label>
<div class="col-sm-10 "> <div class="col-sm-10">
<input type="file" name="file" class="form-control"></input> <input type="file" name="file" class="form-control" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@@ -6,16 +6,20 @@
<div class="form-group" ng-class="{error : !categoryForm.name.$valid}"> <div class="form-group" ng-class="{error : !categoryForm.name.$valid}">
<label class="col-sm-2 control-label">{{ 'new_category.name' | translate }}</label> <label class="col-sm-2 control-label">{{ 'new_category.name' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" class="form-control" name="name" ng-model="cat.name" required></input> <input type="text" class="form-control" name="name" ng-model="cat.name" required />
<span class="help-block" ng-show="!categoryForm.name.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!categoryForm.name.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>
<div class="form-group" ng-class="{error : !categoryForm.category.$valid}"> <div class="form-group" ng-class="{error : !categoryForm.category.$valid}">
<label class="col-sm-2 control-label">{{ 'new_category.parent' | translate }}</label> <label class="col-sm-2 control-label">{{ 'new_category.parent' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<select name="category" ng-model="cat.parentId" class="form-control" <select
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories" required> name="category"
</select> ng-model="cat.parentId"
class="form-control"
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories"
required
></select>
<span class="help-block" ng-show="!categoryForm.category.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!categoryForm.category.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>

View File

@@ -6,24 +6,37 @@
<div class="form-group" ng-class="{error : !subscribeForm.url.$valid}"> <div class="form-group" ng-class="{error : !subscribeForm.url.$valid}">
<label class="col-sm-2 control-label">{{ 'subscribe.feed_url' | translate }}</label> <label class="col-sm-2 control-label">{{ 'subscribe.feed_url' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" name="url" ng-model="sub.url" ng-blur="urlChanged()" placeholder="http://example.com/feed" class="form-control" <input
required ng-disabled="state=='loading'" autofocus></input> type="text"
name="url"
ng-model="sub.url"
ng-blur="urlChanged()"
placeholder="http://example.com/feed"
class="form-control"
required
ng-disabled="state=='loading'"
autofocus
/>
<span class="help-block" ng-show="!subscribeForm.url.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!subscribeForm.url.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>
<div class="form-group" ng-class="{error : !subscribeForm.title.$valid}"> <div class="form-group" ng-class="{error : !subscribeForm.title.$valid}">
<label class="col-sm-2 control-label">{{ 'subscribe.feed_name' | translate }}</label> <label class="col-sm-2 control-label">{{ 'subscribe.feed_name' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" name="title" ng-model="sub.title" class="form-control" required ng-disabled="state=='loading'"></input> <input type="text" name="title" ng-model="sub.title" class="form-control" required ng-disabled="state=='loading'" />
<span class="help-block" ng-show="!subscribeForm.title.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!subscribeForm.title.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>
<div class="form-group" ng-class="{error : !subscribeForm.category.$valid}"> <div class="form-group" ng-class="{error : !subscribeForm.category.$valid}">
<label class="col-sm-2 control-label">{{ 'subscribe.category' | translate }}</label> <label class="col-sm-2 control-label">{{ 'subscribe.category' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<select name="category" ng-model="sub.categoryId" class="form-control" <select
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories" required> name="category"
</select> ng-model="sub.categoryId"
class="form-control"
ng-options="cat.id as cat.name for cat in CategoryService.flatCategories"
required
></select>
<span class="help-block" ng-show="!subscribeForm.category.$valid">{{ 'global.required' | translate }}</span> <span class="help-block" ng-show="!subscribeForm.category.$valid">{{ 'global.required' | translate }}</span>
</div> </div>
</div> </div>

View File

@@ -7,7 +7,12 @@
<label class="col-sm-2 control-label">{{ 'details.feed_url' | translate }}</label> <label class="col-sm-2 control-label">{{ 'details.feed_url' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="checkbox"> <div class="checkbox">
<a ng-show="user.apiKey" href="{{'rest/category/entriesAsFeed?id=all&tag=' + tag + '&apiKey=' + user.apiKey}}" target="_blank">{{ 'global.link' | translate }}</a> <a
ng-show="user.apiKey"
href="{{'rest/category/entriesAsFeed?id=all&tag=' + tag + '&apiKey=' + user.apiKey}}"
target="_blank"
>{{ 'global.link' | translate }}</a
>
<span ng-show="!user.apiKey">{{ 'details.generate_api_key_first' | translate }}</span> <span ng-show="!user.apiKey">{{ 'details.generate_api_key_first' | translate }}</span>
</div> </div>
</div> </div>
@@ -19,5 +24,4 @@
</div> </div>
</div> </div>
</form> </form>
</div> </div>

View File

@@ -14,32 +14,64 @@
</h3> </h3>
</div> </div>
<div infinite-scroll="loadMoreEntries()" infinite-scroll-disabled="busy || !settingsService.settings.readingMode" <div
infinite-scroll-distance="1" id="feed-accordion" ng-class="{'expanded' : settingsService.settings.viewMode == 'expanded' }"> infinite-scroll="loadMoreEntries()"
infinite-scroll-disabled="busy || !settingsService.settings.readingMode"
infinite-scroll-distance="1"
id="feed-accordion"
ng-class="{'expanded' : settingsService.settings.viewMode == 'expanded' }"
>
<div ng-show="message && errorCount > 10">{{ 'view.error_while_loading_feed' | translate }} : {{ message }}</div> <div ng-show="message && errorCount > 10">{{ 'view.error_while_loading_feed' | translate }} : {{ message }}</div>
<div ng-repeat="entry in entries" class="entry entry-font-size-{{font_size}}" id="entry_{{entry.id}}" <div
ng-class="{unread: entry.read == false, current: current==entry, open: isOpen, closed: !isOpen }"> ng-repeat="entry in entries"
class="entry entry-font-size-{{font_size}}"
id="entry_{{entry.id}}"
ng-class="{unread: entry.read == false, current: current==entry, open: isOpen, closed: !isOpen }"
>
<div class="entry-heading" ng-swipe-right="mark(entry, !entry.read)"> <div class="entry-heading" ng-swipe-right="mark(entry, !entry.read)">
<a href="{{entry.url}}" target="_blank" rel="noreferrer" class="entry-heading-link" ng-click="noop($event)" ng-mouseup="entryClicked(entry, $event)"> <a
href="{{entry.url}}"
target="_blank"
rel="noreferrer"
class="entry-heading-link"
ng-click="noop($event)"
ng-mouseup="entryClicked(entry, $event)"
>
<span class="feed-name"> <span class="feed-name">
<span class="star" ng-mouseup="star(entry, !entry.starred, $event)"> <span class="star" ng-mouseup="star(entry, !entry.starred, $event)">
<i ng-class="{'icon-star icon-star-yellow': entry.starred, 'icon-star-empty': !entry.starred}" class="pointer"></i> <i
ng-class="{'icon-star icon-star-yellow': entry.starred, 'icon-star-empty': !entry.starred}"
class="pointer"
></i>
</span> </span>
<favicon url="entry.iconUrl" /> <favicon url="entry.iconUrl" />
{{entry.feedName}} {{entry.feedName}}
</span> </span>
<span class="entry-date">{{entry.date | entryDate}}</span> <span class="entry-date">{{entry.date | entryDate}}</span>
<span class="entry-name" ng-class="{shrink: true, rtl: entry.rtl}" ng-bind-html="entry.title | highlight:keywords | trustHtml"></span> <span
class="entry-name"
ng-class="{shrink: true, rtl: entry.rtl}"
ng-bind-html="entry.title | highlight:keywords | trustHtml"
></span>
</a> </a>
<a href="{{entry.url}}" target="_blank" rel="noreferrer" class="entry-external-link" ng-click="mark(entry, true)"> <a href="{{entry.url}}" target="_blank" rel="noreferrer" class="entry-external-link" ng-click="mark(entry, true)">
<i class="icon-external-link"></i> <i class="icon-external-link"></i>
</a> </a>
</div> </div>
<div class="entry-body" ng-if="settingsService.settings.viewMode == 'expanded' || (isOpen && current == entry)" <div
ng-mouseup="bodyClicked(entry, $event)" ng-class="{rtl: entry.rtl}"> class="entry-body"
ng-if="settingsService.settings.viewMode == 'expanded' || (isOpen && current == entry)"
ng-mouseup="bodyClicked(entry, $event)"
ng-class="{rtl: entry.rtl}"
>
<div class="entry-header"> <div class="entry-header">
<div class="entry-title"> <div class="entry-title">
<a href="{{entry.url}}" target="_blank" rel="noreferrer" ng-bind-html="entry.title | highlight:keywords | trustHtml"></a> <a
href="{{entry.url}}"
target="_blank"
rel="noreferrer"
ng-bind-html="entry.title | highlight:keywords | trustHtml"
></a>
<div class="entry-subtitle"> <div class="entry-subtitle">
<span class="entry-source" ng-if="selectedType == 'category'"> <span class="entry-source" ng-if="selectedType == 'category'">
<span class="entry-source-prefix">{{ 'view.entry_source' | translate }}</span> <span class="entry-source-prefix">{{ 'view.entry_source' | translate }}</span>
@@ -59,9 +91,18 @@
</div> </div>
<div class="entry-body-content"> <div class="entry-body-content">
<div ng-if="!MobileService.mobile" ng-bind-html="entry.content | iframeHttpsRewrite| highlight:keywords | trustHtml"></div> <div
<div ng-if="MobileService.mobile" ng-bind-html="entry.content | iframeHttpsRewrite| highlight:keywords | appendImageTitles | trustHtml"></div> ng-if="!MobileService.mobile"
<div class="entry-enclosure" ng-if="entry.enclosureType && (entry.enclosureUrl && entry.content && entry.content.indexOf(entry.enclosureUrl) == -1)"> ng-bind-html="entry.content | iframeHttpsRewrite| highlight:keywords | trustHtml"
></div>
<div
ng-if="MobileService.mobile"
ng-bind-html="entry.content | iframeHttpsRewrite| highlight:keywords | appendImageTitles | trustHtml"
></div>
<div
class="entry-enclosure"
ng-if="entry.enclosureType && (entry.enclosureUrl && entry.content && entry.content.indexOf(entry.enclosureUrl) == -1)"
>
<video controls ng-if="entry.enclosureType && entry.enclosureType.indexOf('video') == 0"> <video controls ng-if="entry.enclosureType && entry.enclosureType.indexOf('video') == 0">
<source ng-src="{{entry.enclosureUrl | trustUrl}}" type="{{entry.enclosureType}}" /> <source ng-src="{{entry.enclosureUrl | trustUrl}}" type="{{entry.enclosureType}}" />
</video> </video>
@@ -71,7 +112,9 @@
<div ng-if="entry.enclosureType && entry.enclosureType.indexOf('image') == 0"> <div ng-if="entry.enclosureType && entry.enclosureType.indexOf('image') == 0">
<img ng-src="{{entry.enclosureUrl | trustUrl}}" /> <img ng-src="{{entry.enclosureUrl | trustUrl}}" />
</div> </div>
<a ng-href="{{entry.enclosureUrl | trustUrl}}" target="_blank" ng-if="entry.enclosureType" download> {{ 'global.download' | translate }} </a> <a ng-href="{{entry.enclosureUrl | trustUrl}}" target="_blank" ng-if="entry.enclosureType" download>
{{ 'global.download' | translate }}
</a>
</div> </div>
</div> </div>
<div class="entry-buttons form-inline"> <div class="entry-buttons form-inline">
@@ -80,47 +123,90 @@
</div> </div>
<div class="checkbox-inline keep-unread"> <div class="checkbox-inline keep-unread">
<label ng-if="entry.markable" class="pointer"> <label ng-if="entry.markable" class="pointer">
<input type="checkbox" ng-checked="!entry.read" ng-click="mark(entry, !entry.read)" class="mousetrap"></input> <input type="checkbox" ng-checked="!entry.read" ng-click="mark(entry, !entry.read)" class="mousetrap" />
{{ 'view.keep_unread' | translate }} {{ 'view.keep_unread' | translate }}
</label> </label>
</div> </div>
<span class="share-buttons"> <span class="share-buttons">
<a href="mailto:?subject={{entry.title|escape}}&body={{entry.url|escape}}" title="E-mail" popup ng-if="settingsService.settings.email"> <a
href="mailto:?subject={{entry.title|escape}}&body={{entry.url|escape}}"
title="E-mail"
popup
ng-if="settingsService.settings.email"
>
<i class="icon-envelope"></i> <i class="icon-envelope"></i>
</a> </a>
<a href="https://mail.google.com/mail/?view=cm&fs=1&tf=1&source=mailto&su={{entry.title|escape}}&body={{entry.url|escape}}" <a
title="Gmail" popup ng-if="settingsService.settings.gmail"> href="https://mail.google.com/mail/?view=cm&fs=1&tf=1&source=mailto&su={{entry.title|escape}}&body={{entry.url|escape}}"
title="Gmail"
popup
ng-if="settingsService.settings.gmail"
>
<i class="icon-gmail"></i> <i class="icon-gmail"></i>
</a> </a>
<a href="http://www.facebook.com/sharer.php?u={{entry.url|escape}}" title="Facebook" popup ng-if="settingsService.settings.facebook"> <a
href="http://www.facebook.com/sharer.php?u={{entry.url|escape}}"
title="Facebook"
popup
ng-if="settingsService.settings.facebook"
>
<i class="icon-facebook"></i> <i class="icon-facebook"></i>
</a> </a>
<a href="http://twitter.com/share?text={{entry.title|escape}}&url={{entry.url|escape}}" title="Twitter" popup <a
ng-if="settingsService.settings.twitter"> href="http://twitter.com/share?text={{entry.title|escape}}&url={{entry.url|escape}}"
title="Twitter"
popup
ng-if="settingsService.settings.twitter"
>
<i class="icon-twitter"></i> <i class="icon-twitter"></i>
</a> </a>
<a href="https://plus.google.com/share?url={{entry.url|escape}}" title="Google+" popup ng-if="settingsService.settings.googleplus"> <a
href="https://plus.google.com/share?url={{entry.url|escape}}"
title="Google+"
popup
ng-if="settingsService.settings.googleplus"
>
<i class="icon-google-plus"></i> <i class="icon-google-plus"></i>
</a> </a>
<a href="http://www.tumblr.com/share/link?url={{entry.url|escape}}&name={{entry.title|escape}}" title="Tumblr" popup <a
ng-if="settingsService.settings.tumblr"> href="http://www.tumblr.com/share/link?url={{entry.url|escape}}&name={{entry.title|escape}}"
title="Tumblr"
popup
ng-if="settingsService.settings.tumblr"
>
<i class="icon-tumblr"></i> <i class="icon-tumblr"></i>
</a> </a>
<a href="https://getpocket.com/save?url={{entry.url|escape}}&title={{entry.title|escape}}" title="Pocket" popup <a
ng-if="settingsService.settings.pocket"> href="https://getpocket.com/save?url={{entry.url|escape}}&title={{entry.title|escape}}"
title="Pocket"
popup
ng-if="settingsService.settings.pocket"
>
<i class="icon-pocket"></i> <i class="icon-pocket"></i>
</a> </a>
<a href="https://www.instapaper.com/hello2?url={{entry.url|escape}}&title={{entry.title|escape}}" title="Instapaper" popup <a
ng-if="settingsService.settings.instapaper"> href="https://www.instapaper.com/hello2?url={{entry.url|escape}}&title={{entry.title|escape}}"
title="Instapaper"
popup
ng-if="settingsService.settings.instapaper"
>
<i class="icon-instapaper"></i> <i class="icon-instapaper"></i>
</a> </a>
<a href="https://bufferapp.com/add?url={{entry.url|escape}}&text={{entry.title|escape}}" title="Buffer" popup <a
ng-if="settingsService.settings.buffer"> href="https://bufferapp.com/add?url={{entry.url|escape}}&text={{entry.title|escape}}"
title="Buffer"
popup
ng-if="settingsService.settings.buffer"
>
<i class="icon-buffer"></i> <i class="icon-buffer"></i>
</a> </a>
<a href="http://www.readability.com/save?url={{entry.url|escape}}" title="Readability" popup <a
ng-if="settingsService.settings.readability"> href="http://www.readability.com/save?url={{entry.url|escape}}"
title="Readability"
popup
ng-if="settingsService.settings.readability"
>
<i class="icon-couch"></i> <i class="icon-couch"></i>
</a> </a>
</span> </span>

View File

@@ -18,16 +18,34 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label" for="password">{{ 'profile.change_password' | translate }}</label> <label class="col-sm-2 control-label" for="password">{{ 'profile.change_password' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="password" name="password" id="password" ng-model="user.password" class="form-control" ng-minlength="6" autocomplete="off" /> <input
type="password"
name="password"
id="password"
ng-model="user.password"
class="form-control"
ng-minlength="6"
autocomplete="off"
/>
<span class="help-inline" ng-show="profileForm.password.$error.minlength">{{ 'profile.minimum_6_chars' | translate }}</span> <span class="help-inline" ng-show="profileForm.password.$error.minlength">{{ 'profile.minimum_6_chars' | translate }}</span>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-2 control-label" for="password">{{ 'profile.confirm_password' | translate }}</label> <label class="col-sm-2 control-label" for="password">{{ 'profile.confirm_password' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="password" class="form-control" name="password_c" id="password_c" ng-model="password_c" <input
ui-validate="'$value==user.password'" ui-validate-watch="'user.password'" autocomplete="off"> type="password"
<span class="help-inline" ng-show="profileForm.password_c.$error.validator">{{ 'profile.passwords_do_not_match' | translate }}</span> class="form-control"
name="password_c"
id="password_c"
ng-model="password_c"
ui-validate="'$value==user.password'"
ui-validate-watch="'user.password'"
autocomplete="off"
/>
<span class="help-inline" ng-show="profileForm.password_c.$error.validator"
>{{ 'profile.passwords_do_not_match' | translate }}</span
>
</div> </div>
</div> </div>
@@ -42,7 +60,7 @@
<label class="col-sm-2 control-label" for="password">{{ 'profile.generate_new_api_key' | translate }}</label> <label class="col-sm-2 control-label" for="password">{{ 'profile.generate_new_api_key' | translate }}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="checkbox"> <div class="checkbox">
<input type="checkbox" name="newApiKey" id="newApiKey" ng-model="newApiKey"> <input type="checkbox" name="newApiKey" id="newApiKey" ng-model="newApiKey" />
<span class="help-inline">{{ 'profile.generate_new_api_key_info' | translate }}</span> <span class="help-inline">{{ 'profile.generate_new_api_key_info' | translate }}</span>
</div> </div>
</div> </div>
@@ -57,8 +75,14 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">{{ 'global.save' | translate }}</button> <button type="submit" class="btn btn-primary">{{ 'global.save' | translate }}</button>
<button type="button" class="btn btn-danger" ng-click="deleteAccount()" <button
confirm-click="'profile.delete_account_confirmation' | translate">{{ 'profile.delete_account' | translate }}</button> type="button"
class="btn btn-danger"
ng-click="deleteAccount()"
confirm-click="'profile.delete_account_confirmation' | translate"
>
{{ 'profile.delete_account' | translate }}
</button>
<button type="button" class="btn btn-default" ng-click="cancel()">{{ 'global.cancel' | translate }}</button> <button type="button" class="btn btn-default" ng-click="cancel()">{{ 'global.cancel' | translate }}</button>
</div> </div>
</div> </div>

View File

@@ -20,12 +20,17 @@
<div class="form-horizontal"> <div class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label>{{ 'settings.general.language' | translate }}</label> <label>{{ 'settings.general.language' | translate }}</label>
<select name="language" ng-model="settings.language" class="form-control" <select
ng-options="id as label for (id,label) in langs" required> name="language"
</select> ng-model="settings.language"
class="form-control"
ng-options="id as label for (id,label) in langs"
required
></select>
<span class="help-block"> <span class="help-block">
<a href="https://github.com/Athou/commafeed#translate-commafeed-into-your-language" target="_blank"> <a href="https://github.com/Athou/commafeed#translate-commafeed-into-your-language" target="_blank">
{{ 'settings.general.language_contribute' | translate }} </a> {{ 'settings.general.language_contribute' | translate }}
</a>
</span> </span>
</div> </div>
<div class="checkbox"> <div class="checkbox">
@@ -125,13 +130,14 @@
<label>{{ 'settings.theme' | translate }}</label> <label>{{ 'settings.theme' | translate }}</label>
<select ng-model="settings.theme" ng-options="theme for theme in themes" class="form-control"></select> <select ng-model="settings.theme" ng-options="theme for theme in themes" class="form-control"></select>
<span class="help-block"> <span class="help-block">
<a href="https://github.com/Athou/commafeed#themes" target="_blank"> {{ 'settings.submit_your_theme' | translate }} </a> <a href="https://github.com/Athou/commafeed#themes" target="_blank">
{{ 'settings.submit_your_theme' | translate }}
</a>
</span> </span>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{ 'settings.custom_css' | translate }}</label> <label>{{ 'settings.custom_css' | translate }}</label>
<textarea ng-model="settings.customCss" class="form-control" rows="20"> <textarea ng-model="settings.customCss" class="form-control" rows="20"> </textarea>
</textarea>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -2,7 +2,7 @@
<div class="row header" ng-controller="LoginCtrl"> <div class="row header" ng-controller="LoginCtrl">
<div class="pull-left"> <div class="pull-left">
<a> <a>
<img src="images/logo_2.png"></img> <img src="images/logo_2.png" />
</a> </a>
</div> </div>
<div class="pull-right tagline">Bloat-free feed reader</div> <div class="pull-right tagline">Bloat-free feed reader</div>
@@ -23,11 +23,11 @@
<form ng-submit="login()"> <form ng-submit="login()">
<div class="form-group"> <div class="form-group">
<label for="username">User Name or E-mail</label> <label for="username">User Name or E-mail</label>
<input type="text" name="username" class="form-control" ng-model="model.name"></input> <input type="text" name="username" class="form-control" ng-model="model.name" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password">Password</label> <label for="password">Password</label>
<input type="password" name="password" class="form-control" ng-model="model.password"></input> <input type="password" name="password" class="form-control" ng-model="model.password" />
</div> </div>
<div> <div>
<input type="submit" class="btn btn-primary" value="Log in" /> <input type="submit" class="btn btn-primary" value="Log in" />
@@ -41,7 +41,7 @@
<form ng-submit="recover()"> <form ng-submit="recover()">
<div class="form-group"> <div class="form-group">
<label for="email">Email</label> <label for="email">Email</label>
<input type="email" name="email" class="form-control" ng-model="recovery_model.email" focus="true"></input> <input type="email" name="email" class="form-control" ng-model="recovery_model.email" focus="true" />
</div> </div>
<div> <div>
<input type="submit" class="btn btn-primary" value="Recover" /> <input type="submit" class="btn btn-primary" value="Recover" />
@@ -58,15 +58,15 @@
<form autocomplete="off" ng-submit="register()"> <form autocomplete="off" ng-submit="register()">
<div class="form-group"> <div class="form-group">
<label>User Name</label> <label>User Name</label>
<input type="text" class="form-control" ng-model="model.name"></input> <input type="text" class="form-control" ng-model="model.name" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Password</label> <label>Password</label>
<input type="password" class="form-control" ng-model="model.password"></input> <input type="password" class="form-control" ng-model="model.password" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Email address (used for password recovery only)</label> <label>Email address (used for password recovery only)</label>
<input type="email" class="form-control" ng-model="model.email"></input> <input type="email" class="form-control" ng-model="model.email" />
</div> </div>
<div> <div>
<input type="submit" class="btn btn-primary" value="Register" /> <input type="submit" class="btn btn-primary" value="Register" />
@@ -93,17 +93,21 @@
<a href="api/" target="_blank">documentation</a> <a href="api/" target="_blank">documentation</a>
</span> </span>
<span class="pull-right"> <span class="pull-right">
<a href="https://twitter.com/CommaFeed" class="twitter-follow-button" data-show-count="false" data-size="large">Follow @CommaFeed</a> <a href="https://twitter.com/CommaFeed" class="twitter-follow-button" data-show-count="false" data-size="large"
>Follow @CommaFeed</a
>
<script> <script>
!function(d, s, id) { !(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0], p = /^http:/.test(d.location) ? 'http' : 'https'; var js,
fjs = d.getElementsByTagName(s)[0],
p = /^http:/.test(d.location) ? "http" : "https"
if (!d.getElementById(id)) { if (!d.getElementById(id)) {
js = d.createElement(s); js = d.createElement(s)
js.id = id; js.id = id
js.src = p + '://platform.twitter.com/widgets.js'; js.src = p + "://platform.twitter.com/widgets.js"
fjs.parentNode.insertBefore(js, fjs); fjs.parentNode.insertBefore(js, fjs)
} }
}(document, 'script', 'twitter-wjs'); })(document, "script", "twitter-wjs")
</script> </script>
</span> </span>
</div> </div>