diff --git a/.gitignore b/.gitignore
index de90324..1dd5375 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,5 +3,5 @@
node_modules
.sass-cache
-*.sublime-project
-*.sublime-workspace
+
+scripts/modules.js
diff --git a/gulpfile.js b/gulpfile.js
index 30e64f8..1b61167 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -6,7 +6,8 @@ var gulp = require('gulp'),
rename = require('gulp-rename'),
concat = require('gulp-concat-util'),
prefix = require('gulp-autoprefixer'),
- groupMQ = require('gulp-group-css-media-queries');
+ groupMQ = require('gulp-group-css-media-queries'),
+ jade = require('gulp-jade');
var paths = {
styles: 'styles/**/*.scss',
@@ -19,11 +20,20 @@ var paths = {
'scripts/functions.js',
'scripts/actions.js',
'scripts/listeners.js',
- 'scripts/init.js'
+ 'scripts/init.js',
+ 'scripts/modules.js'
],
+ scriptModules: {
+ root: 'scripts/modules/**/*.js',
+ dest: 'scripts'
+ },
+ templates: {
+ root: 'templates/index.jade'
+ },
watch: {
- scripts: 'scripts/**/*.js',
- styles: 'styles/**/*.scss'
+ scripts: ['scripts/**/*.js', '!scripts/modules.js'],
+ styles: 'styles/**/*.scss',
+ templates: 'templates/**/*.jade'
},
root: './',
distribution: 'dist/'
@@ -45,7 +55,15 @@ gulp.task('styles', function() {
.pipe(gulp.dest(paths.distribution));
});
-gulp.task('scripts', function() {
+gulp.task('scripts-modules', function() {
+ return gulp.src(paths.scriptModules.root)
+ .pipe(jshint())
+ .pipe(jshint.reporter('default'))
+ .pipe(concat('modules.js'))
+ .pipe(gulp.dest(paths.scriptModules.dest));
+});
+
+gulp.task('scripts', ['scripts-modules'], function() {
return gulp.src(paths.scripts)
.pipe(jshint())
.pipe(jshint.reporter('default'))
@@ -61,9 +79,18 @@ gulp.task('scripts', function() {
.pipe(gulp.dest(paths.distribution));
});
-gulp.task('default', ['styles', 'scripts']);
+gulp.task('templates', function() {
+ return gulp.src(paths.templates.root)
+ .pipe(jade({
+ pretty: true
+ }))
+ .pipe(gulp.dest(paths.root));
+});
+
+gulp.task('default', ['styles', 'scripts', 'templates']);
gulp.task('dev', function() {
gulp.watch(paths.watch.styles, ['styles']);
gulp.watch(paths.watch.scripts, ['scripts']);
+ gulp.watch(paths.watch.templates, ['templates']);
});
diff --git a/img/cancel.png b/img/cancel.png
deleted file mode 100644
index df8832f..0000000
Binary files a/img/cancel.png and /dev/null differ
diff --git a/img/close.png b/img/close.png
deleted file mode 100644
index 151ebe7..0000000
Binary files a/img/close.png and /dev/null differ
diff --git a/index.html b/index.html
index eac0c18..385f796 100644
--- a/index.html
+++ b/index.html
@@ -52,23 +52,17 @@
+
-
-
-
hot
-
new
-
controversial
-
top
-
About
Export Data
Import Data
- Mnml
+ Theme
@@ -76,15 +70,23 @@
+
diff --git a/package.json b/package.json
index 8dd99c0..2caca56 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,8 @@
"gulp-jshint": "~1.6.3",
"gulp-watch": "^0.6.8",
"gulp-concat-util": "~0.5.1",
- "gulp-group-css-media-queries": "~1.0.1"
+ "gulp-group-css-media-queries": "~1.0.1",
+ "gulp-jade": "~0.11.0"
},
"scripts": {
"start": "gulp dev"
diff --git a/reeddit.appcache b/reeddit.appcache
index b363975..e4f5d7b 100644
--- a/reeddit.appcache
+++ b/reeddit.appcache
@@ -10,8 +10,6 @@ dist/app.min.css
# images
/img/add.png
/img/alienHead.png
-/img/cancel.png
-/img/close.png
/img/comment_24.png
/img/darkdenim3.png
/img/delete.png
diff --git a/scripts/actions.js b/scripts/actions.js
index 123dcee..d37ba25 100644
--- a/scripts/actions.js
+++ b/scripts/actions.js
@@ -187,7 +187,7 @@ tappable("#wide-refresh", {
tappable("#sub-title", {
onTap: function() {
- if ((!isDesktop && loadingLinks) || isLargeScreen) return;
+ if ((!isDesktop && loadingLinks)) return;
V.Actions.moveMenu(showingMenu ? move.left : move.right);
}
});
@@ -208,8 +208,11 @@ tappable("#more-links", {
onTap: function() {
doByCurrentSelection(function() {
var url;
- if (M.currentSelection.name.toUpperCase() === 'frontPage'.toUpperCase()) url = urlInit + "r/" + M.Subreddits.getAllString() + "/";
- else url = urlInit + "r/" + M.currentSelection.name + "/";
+ if (M.currentSelection.name.toLowerCase() === 'frontpage') {
+ url = urlInit + "r/" + M.Subreddits.getAllSubsString() + "/";
+ } else {
+ url = urlInit + "r/" + M.currentSelection.name + "/";
+ }
C.Posts.load(url, '&after=' + M.Posts.idLast);
}, function() {
var channel = M.Channels.getByName(M.currentSelection.name);
@@ -262,7 +265,7 @@ tappable('.btn-add-sub', {
subTitle = $(".subreddit-title", parent);
subTitle.css("color", "#2b9900"); // 'adding sub' little UI feedback
var newSub = subTitle.text();
- V.Subreddits.insert(newSub);
+ C.Subreddits.add(newSub);
},
activeClass: 'button-active'
});
@@ -373,25 +376,29 @@ V.detailWrap.on('click', '#comments-container a, #selftext a', function(ev) {
});
// Swipes
-V.detailView.swipeRight(function() {
- if (isWideScreen) return;
- location.hash = "#";
-});
-
-V.mainView.swipeRight(function() {
- if ((!isDesktop && loadingLinks) || isLargeScreen) return;
- if (currentView === view.main) V.Actions.moveMenu(move.right);
-});
-
-V.mainView.swipeLeft(function() {
- if ((!isDesktop && loadingLinks) || isLargeScreen) return;
- if (showingMenu) V.Actions.moveMenu(move.left);
-});
-
-V.mainView.on("swipeLeft", ".link", function() {
- if (isWideScreen) return;
- if (!showingMenu) {
- var id = $(this).data("id");
- goToComments(id);
- }
-});
+if (isMobile) {
+ if (!(isiPhone && isiOS7)) {
+ V.detailView.swipeRight(function() {
+ if (isWideScreen) return;
+ location.hash = "#";
+ });
+ }
+
+ V.mainView.swipeRight(function() {
+ if ((!isDesktop && loadingLinks) || isLargeScreen) return;
+ if (currentView === view.main) V.Actions.moveMenu(move.right);
+ });
+
+ V.mainView.swipeLeft(function() {
+ if ((!isDesktop && loadingLinks) || isLargeScreen) return;
+ if (showingMenu) V.Actions.moveMenu(move.left);
+ });
+
+ V.mainView.on("swipeLeft", ".link", function() {
+ if (isWideScreen) return;
+ if (!showingMenu) {
+ var id = $(this).data("id");
+ goToComments(id);
+ }
+ });
+}
diff --git a/scripts/controller.js b/scripts/controller.js
index 53b9a9e..6631ad8 100644
--- a/scripts/controller.js
+++ b/scripts/controller.js
@@ -40,6 +40,12 @@ var C = { // "Controller"
V.Posts.show(links, paging);
M.Posts.setList(links);
+ if (isWideScreen) {
+ var id = getCommentHash();
+ if (id) {
+ V.Actions.setSelectedLink(id);
+ }
+ }
}
},
Comments: {
@@ -171,18 +177,31 @@ var C = { // "Controller"
loadPosts: function(sub) {
if (sub !== M.currentSelection.name || editingSubs) {
var url;
- if (sub.toUpperCase() === 'frontPage'.toUpperCase()) url = urlInit + "r/" + M.Subreddits.getAllString() + "/";
- else url = urlInit + "r/" + sub + "/";
+ if (sub.toLowerCase() === 'frontpage') {
+ url = urlInit + "r/" + M.Subreddits.getAllSubsString() + "/";
+ } else {
+ url = urlInit + "r/" + sub + "/";
+ }
C.Posts.load(url);
C.currentSelection.setSubreddit(sub);
}
V.Actions.setSubTitle(sub);
},
- remove: function(sub) {
- M.Subreddits.remove(sub);
- V.Subreddits.remove(sub);
- if (M.currentSelection.type === selection.sub && M.currentSelection.name === sub) C.currentSelection.setSubreddit('frontPage'); // If it was the current selection
- },
+ remove: function(sub) {
+ M.Subreddits.remove(sub);
+ V.Subreddits.remove(sub);
+ if (M.currentSelection.type === selection.sub &&
+ M.currentSelection.name === sub) { // If it was the current selection
+ C.currentSelection.setSubreddit('frontPage');
+ }
+ },
+ add: function(newSub) {
+ if (M.Subreddits.listHasSub(newSub)) {
+ return;
+ }
+ M.Subreddits.add(newSub);
+ V.Subreddits.insert(newSub);
+ },
addFromNewForm: function() {
var txtSub = $id("txt-new-sub"),
subName = txtSub.value;
@@ -191,6 +210,12 @@ var C = { // "Controller"
V.Anims.shakeForm();
return;
}
+ if (M.Subreddits.listHasSub(subName)) {
+ txtSub.value = "";
+ txtSub.setAttribute("placeholder", subName + " already added!");
+ V.Anims.shakeForm();
+ return;
+ }
subName = subName.trim();
diff --git a/scripts/functions.js b/scripts/functions.js
index 037d5a5..b4ad3ac 100644
--- a/scripts/functions.js
+++ b/scripts/functions.js
@@ -1,20 +1,8 @@
-function checkWideScreen() {
- return win.matchMedia("(min-width: 1000px)").matches;
-}
-
-function checkLargeScreen() {
- return win.matchMedia("(min-width: 490px)").matches;
-}
-
function triggerClick(url) {
var a = doc.createElement('a');
a.setAttribute("href", url);
a.setAttribute("target", "_blank");
- //var dispatch = doc.createEvent("HTMLEvents");
- //dispatch.initEvent("click", true, true);
- //a.dispatchEvent(dispatch);
-
var clickEvent = new MouseEvent("click", {
"view": window,
"bubbles": true,
@@ -33,12 +21,19 @@ function openPost(url, id) {
}
}
+function getCommentHash() {
+ var match = location.hash.match(/(#comments:)((?:[a-zA-Z0-9]*))/);
+ if (match && match[2]) {
+ return match[2];
+ }
+}
+
function goToCommentFromHash() {
- var match = location.hash.match(/(#comments:)((?:[a-zA-Z0-9]*))/);
- if (match && match[2]) {
- var id = match[2];
- C.Comments.show(id);
- }
+ var id = getCommentHash();
+ C.Comments.show(id);
+ if (isWideScreen) {
+ V.Actions.setSelectedLink(id);
+ }
}
function checkImageLink(url) {
@@ -101,8 +96,11 @@ function goToComments(id) {
function refreshCurrentStream() {
if (editingSubs) return;
doByCurrentSelection(function() { // if it's subreddit
- if (M.currentSelection.name.toUpperCase() === 'frontPage'.toUpperCase()) C.Posts.load(urlInit + "r/" + M.Subreddits.getAllString() + "/");
- else C.Posts.load(urlInit + "r/" + M.currentSelection.name + "/");
+ if (M.currentSelection.name.toLowerCase() === 'frontpage') {
+ C.Posts.load(urlInit + "r/" + M.Subreddits.getAllSubsString() + "/");
+ } else {
+ C.Posts.load(urlInit + "r/" + M.currentSelection.name + "/");
+ }
}, function() { // if it's channel
C.Channels.loadPosts(M.Channels.getByName(M.currentSelection.name));
});
diff --git a/scripts/globals.js b/scripts/globals.js
index d1f17ac..e0e3174 100644
--- a/scripts/globals.js
+++ b/scripts/globals.js
@@ -23,10 +23,7 @@ var editingSubs = false,
loadingComments = false,
loadingLinks = false,
currentThread,
- isWideScreen = checkWideScreen(),
- isLargeScreen = checkLargeScreen(),
- isiPad,
- scrollFix,
+ iPadScrollFix,
currentSortingChoice = 'hot',
mnml = false,
updateBackup = 1,
@@ -55,9 +52,23 @@ var editingSubs = false,
},
currentView = view.main;
-var defaultSubs = ["frontPage", "pics", "IAmA", "AskReddit", "worldNews", "todayilearned", "tech", "science", "reactiongifs", "books", "explainLikeImFive", "videos", "AdviceAnimals", "funny", "aww", "earthporn"];
+var defaultSubs = ["frontPage", "all", "pics", "IAmA", "AskReddit", "worldNews", "todayilearned", "tech", "science", "reactiongifs", "books", "explainLikeImFive", "videos", "AdviceAnimals", "funny", "aww", "earthporn"];
var defaultChannel = {
name: "Media",
subs: ["movies", "television", "music", "games"]
};
+
+// Breakpoints
+var wideScreenBP = win.matchMedia("(min-width: 1000px)"),
+ largeScreenBP = win.matchMedia("(min-width: 490px)"),
+ isWideScreen = wideScreenBP.matches,
+ isLargeScreen = largeScreenBP.matches;
+
+// Browser Detection
+var UA = win.navigator.userAgent,
+ isMobile = !isDesktop,
+ isiPhone = /iP(hone|od)/.test(UA),
+ isiPad = /iPad/.test(UA),
+ isiOS = isiPad || isiPhone,
+ isiOS7 = isiOS && parseInt(UA.match(/ OS (\d+)_/i)[1], 10) >= 7;
diff --git a/scripts/init.js b/scripts/init.js
index 5284d34..c0ca838 100644
--- a/scripts/init.js
+++ b/scripts/init.js
@@ -20,7 +20,7 @@ doByCurrentSelection(
// Load links
if (M.currentSelection.name.toUpperCase() === 'frontPage'.toUpperCase()) {
C.currentSelection.setSubreddit('frontPage');
- C.Posts.load(urlInit + "r/" + M.Subreddits.getAllString() + "/");
+ C.Posts.load(urlInit + "r/" + M.Subreddits.getAllSubsString() + "/");
} else {
C.Posts.load(urlInit + "r/" + M.currentSelection.name + "/");
}
@@ -53,19 +53,18 @@ if (!isDesktop) {
doc.getElementsByTagName('header')[0].addEventListener(touch, function(e) {
if (showingMenu) e.preventDefault(); // Cheat temporal, para evitar que las vistas hagan overflow
}, false);
- isiPad = /iPad/.test(UA);
if (isiPad) {
- scrollFix = function() {
+ iPadScrollFix = function() {
// This slight height change makes the menu container 'overflowy', to allow scrolling again on iPad - weird bug
var nextHeight = '36px' === $('.menu-desc').css('height') ? '35px' : '36px';
setTimeout(function() {
$('.menu-desc').css('height', nextHeight);
}, 500);
};
- scrollFix();
+ iPadScrollFix();
}
- // apply iOS 7+ theme
- if (/iPhone|iPod|iPad/.test(UA) && parseInt(UA.match(/ OS (\d+)_/i)[1], 10) >= 7) {
+ if (isiOS7) {
+ // apply iOS 7+ theme
if (!isMnml) V.Actions.switchMnml(true, true);
body.classList.add("ios7");
}
diff --git a/scripts/listeners.js b/scripts/listeners.js
index 4d27f15..e319f94 100644
--- a/scripts/listeners.js
+++ b/scripts/listeners.js
@@ -19,23 +19,52 @@ if (win.applicationCache)
// Do stuff after finishing resizing the windows
win.addEventListener("resizeend", function() {
- isWideScreen = checkWideScreen();
- isLargeScreen = checkLargeScreen();
+ isWideScreen = wideScreenBP.matches;
+ isLargeScreen = largeScreenBP.matches;
scrollTop();
if (isLargeScreen && showingMenu) V.Actions.moveMenu(move.left);
- if (isiPad) scrollFix();
+ if (isiPad) iPadScrollFix();
}, false);
+if (isiPhone && isiOS7) {
+ var hasSwiped = false,
+ swipeClass = 'from-swipe';
+ document.addEventListener('touchstart', function(ev) {
+ var touchX = ev.targetTouches[0].clientX;
+ hasSwiped = (touchX < 10 || touchX > window.innerWidth - 10);
+ });
+ document.addEventListener('touchend', function() {
+ hasSwiped = false;
+ });
+}
+
// Pseudo-hash-router
win.addEventListener('hashchange', function() {
- if (location.hash === "") {
- V.Actions.backToMainView();
- $('.link.link-selected').removeClass('link-selected');
+ if (isiPhone && isiOS7) {
+ // Switch `transition-duration` class,
+ // to stop animation when swiping
+ if (hasSwiped) {
+ V.mainView.addClass(swipeClass);
+ V.detailView.addClass(swipeClass);
+ V.btnNavBack.addClass(swipeClass);
+ V.subtitle.addClass(swipeClass);
+ } else {
+ V.mainView.removeClass(swipeClass);
+ V.detailView.removeClass(swipeClass);
+ V.btnNavBack.removeClass(swipeClass);
+ V.subtitle.removeClass(swipeClass);
+ }
+ hasSwiped = false;
+ }
+ // Handle Hash Changes
+ if (location.hash === "") { // To Main View
+ V.Actions.backToMainView();
+ V.Actions.clearSelectedLink();
V.Actions.setDetailFooter("");
- setTimeout(function() {
- V.detailWrap.empty();
- }, isWideScreen ? 1 : 301);
- } else {
+ setTimeout(function() {
+ V.detailWrap.empty();
+ }, isWideScreen ? 1 : 301);
+ } else { // To Comment View
goToCommentFromHash();
}
}, false);
diff --git a/scripts/model.js b/scripts/model.js
index 29212f6..b65d63e 100644
--- a/scripts/model.js
+++ b/scripts/model.js
@@ -31,13 +31,11 @@ var M = { // Model
},
Subreddits: {
list: [],
- add: function(sub) {
- if (!M.Subreddits.listHasSub(sub)) {
- M.Subreddits.list.push(sub);
- store.setItem("subreeddits", JSON.stringify(M.Subreddits.list));
- updateBackup = 1;
- }
- },
+ add: function(sub) {
+ M.Subreddits.list.push(sub);
+ store.setItem("subreeddits", JSON.stringify(M.Subreddits.list));
+ updateBackup = 1;
+ },
setList: function(subs) {
M.Subreddits.list = subs;
store.setItem("subreeddits", JSON.stringify(M.Subreddits.list));
@@ -49,18 +47,29 @@ var M = { // Model
store.setItem("subreeddits", JSON.stringify(M.Subreddits.list));
updateBackup = 1;
},
- listHasSub: function(sub) {
- if (M.Subreddits.list) {
- var i = M.Subreddits.list.indexOf(sub);
- return i > -1;
- }
- return false;
- },
- getAllString: function() {
- var allSubs = '';
+ listHasSub: function(newSub) {
+ if (M.Subreddits.list) {
+ newSub = newSub.toLowerCase();
+ for(var i = M.Subreddits.list.length; --i;) {
+ var sub = M.Subreddits.list[i];
+ if (sub.toLowerCase() === newSub) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+ },
+ getAllSubsString: function() {
+ var allSubs = '',
+ frontPage = 'frontpage',
+ all = 'all';
for (var i = 0; i < M.Subreddits.list.length; i++) {
- var sub = M.Subreddits.list[i];
- if (sub.toUpperCase() === 'frontPage'.toUpperCase()) continue;
+ var sub = M.Subreddits.list[i].toLowerCase();
+ if (sub === frontPage ||
+ sub === all) {
+ continue;
+ }
allSubs += sub + '+';
}
return allSubs.substring(0, allSubs.length - 1);
@@ -121,4 +130,4 @@ var M = { // Model
store.setItem('currentSelection', JSON.stringify(M.currentSelection));
}
}
-};
\ No newline at end of file
+};
diff --git a/scripts/modules/sort-switch.js b/scripts/modules/sort-switch.js
new file mode 100644
index 0000000..3c87b2f
--- /dev/null
+++ b/scripts/modules/sort-switch.js
@@ -0,0 +1,29 @@
+(function() {
+ 'use strict';
+
+ // Imports
+ /* global C */
+
+ var el = {
+ main: $('.js-sort-switch-main'),
+ wrap: $('.js-sort-switch-wrap')
+ };
+
+ var classes = {
+ new: 'sort-switch--new'
+ };
+
+ // Initial State
+ var isHot = true;
+
+ el.main.click(function() {
+ isHot = !isHot;
+ C.Sorting.change(isHot ? 'hot' : 'new');
+ if (isHot) {
+ el.main.removeClass(classes.new);
+ } else {
+ el.main.addClass(classes.new);
+ }
+ });
+
+})();
diff --git a/scripts/templates.js b/scripts/templates.js
index 986d229..7d0c549 100644
--- a/scripts/templates.js
+++ b/scripts/templates.js
@@ -12,12 +12,12 @@ var T = { // Templates
},
linkSummary: "