Merge pull request #484 from gvn/pretty

Automating code style enforcement, stricter JSHint, cleaned existing codebase
This commit is contained in:
gvn lazar suntop 2013-11-06 13:20:14 -08:00
Родитель eba546cbe3 abcec47f92
Коммит cb49fc6738
35 изменённых файлов: 1304 добавлений и 1203 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -1,3 +1,4 @@
TODO.txt
node_modules/
bower_components/
.env

17
.jsbeautifyrc Normal file
Просмотреть файл

@ -0,0 +1,17 @@
{
"indent_size": 2,
"indent_char": " ",
"indent_level": 0,
"indent_with_tabs": false,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"jslint_happy": true,
"brace_style": "collapse",
"keep_array_indentation": false,
"keep_function_indentation": false,
"space_before_conditional": true,
"break_chained_methods": false,
"eval_code": false,
"unescape_strings": false,
"wrap_line_length": 0
}

21
.jshintrc Normal file
Просмотреть файл

@ -0,0 +1,21 @@
{
"globals": {
"module": true,
"define": true,
"requirejs": true,
"require": true,
"Packery": true
},
"bitwise": true,
"curly": true,
"eqeqeq": true,
"freeze": true,
"immed": true,
"indent": 2,
"latedef": true,
"newcap": true,
"noempty": true,
"nonew": true,
"trailing": true,
"undef": true
}

Просмотреть файл

@ -1,7 +1,37 @@
module.exports = function( grunt ) {
grunt.initConfig({
pkg: grunt.file.readJSON( "package.json" ),
module.exports = function (grunt) {
// Node and client side JS have slightly different JSHint directives
// We'll create 2 versions with .jshintrc as a baseline
var browserJSHint = grunt.file.readJSON('.jshintrc');
var nodeJSHint = {};
// Create a copy of browserJSHint
for (var prop in browserJSHint) {
nodeJSHint[prop] = browserJSHint[prop];
}
// Don't throw errors for expected Node globals
nodeJSHint.node = true;
// Don't throw errors for expected browser globals
browserJSHint.browser = true;
var clientSideJS = [
'public/js/**/*.js',
'!public/js/lib/**'
];
var nodeJS = [
'Gruntfile.js',
'app.js',
'lib/**/*.js',
'!lib/events/**',
'routes/**/*.js'
];
var allJS = clientSideJS.concat(nodeJS);
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
recess: {
dist: {
options: {
@ -12,27 +42,46 @@ module.exports = function( grunt ) {
strictPropertyOrder: false
},
src: [
"public/css/style.less",
"public/css/make-details.less"
'public/css/style.less',
'public/css/make-details.less'
]
}
},
jsbeautifier: {
modify: {
src: allJS,
options: {
config: '.jsbeautifyrc'
}
},
verify: {
src: allJS,
options: {
mode: 'VERIFY_ONLY',
config: '.jsbeautifyrc'
}
}
},
jshint: {
files: [
"Gruntfile.js",
"app.js",
"lib/**/*.js",
"package.json",
"public/js/**/*.js",
"!public/js/lib/**",
"!lib/events/**",
"routes/**/*.js"
]
browser: {
src: clientSideJS,
options: browserJSHint
},
node: {
src: nodeJS,
options: nodeJSHint
}
}
});
grunt.loadNpmTasks( "grunt-recess" );
grunt.loadNpmTasks( "grunt-contrib-jshint" );
grunt.loadNpmTasks('grunt-recess');
grunt.loadNpmTasks('grunt-jsbeautifier');
grunt.loadNpmTasks('grunt-contrib-jshint');
// Verify code
grunt.registerTask('default', ['recess', 'jsbeautifier:verify', 'jshint']);
// Clean code (Run before commit)
grunt.registerTask('clean', ['jsbeautifier:modify', 'jshint']);
grunt.registerTask( "default", [ "recess", "jshint" ]);
};

317
app.js
Просмотреть файл

@ -1,30 +1,32 @@
if ( process.env.NEW_RELIC_HOME ) {
require( 'newrelic' );
/* global log, LOG_CRIT, LOG_ERR */
if (process.env.NEW_RELIC_HOME) {
require('newrelic');
}
var express = require( "express" ),
domain = require( "domain" ),
cluster = require( "cluster" ),
habitat = require( "habitat" ),
helmet = require( "helmet" ),
nunjucks = require( "nunjucks" ),
path = require( "path" ),
lessMiddleWare = require( "less-middleware" ),
i18n = require( "webmaker-i18n" ),
navigation = require( "./navigation" );
var express = require("express"),
domain = require("domain"),
cluster = require("cluster"),
habitat = require("habitat"),
helmet = require("helmet"),
nunjucks = require("nunjucks"),
path = require("path"),
lessMiddleWare = require("less-middleware"),
i18n = require("webmaker-i18n"),
navigation = require("./navigation");
habitat.load();
var app = express(),
env = new habitat(),
nunjucksEnv = new nunjucks.Environment( new nunjucks.FileSystemLoader( path.join( __dirname, 'views' )), {
autoescape: true
}),
NODE_ENV = env.get( "NODE_ENV" ),
WWW_ROOT = path.resolve( __dirname, "public" ),
server;
env = new habitat(),
nunjucksEnv = new nunjucks.Environment(new nunjucks.FileSystemLoader(path.join(__dirname, 'views')), {
autoescape: true
}),
NODE_ENV = env.get("NODE_ENV"),
WWW_ROOT = path.resolve(__dirname, "public"),
server;
nunjucksEnv.addFilter("instantiate", function(input) {
nunjucksEnv.addFilter("instantiate", function (input) {
var tmpl = new nunjucks.Template(input);
return tmpl.render(this.getVariables());
});
@ -35,13 +37,13 @@ nunjucksEnv.addFilter("instantiate", function(input) {
// if the key name is "some input": "My name is {{name}}"
// tmpl.render(localVar) will try to render it with the available variable from the
// `localVar` object and return something like `My name is Ali`
nunjucksEnv.addFilter("localVar", function(input, localVar) {
nunjucksEnv.addFilter("localVar", function (input, localVar) {
var tmpl = new nunjucks.Template(input);
return tmpl.render(localVar);
});
// Make the client-side gettext possible!!
nunjucksEnv.addFilter("gettext", function(string) {
nunjucksEnv.addFilter("gettext", function (string) {
return this.lookup('gettext')(string);
});
@ -61,162 +63,165 @@ nunjucksEnv.addFilter("getSection", function (pageId) {
return "";
});
if ( !( env.get( "MAKE_ENDPOINT" ) && env.get( "MAKE_PRIVATEKEY" ) && env.get( "MAKE_PUBLICKEY" ) ) ) {
throw new Error( "MakeAPI Config setting invalid or missing!" );
if (!(env.get("MAKE_ENDPOINT") && env.get("MAKE_PRIVATEKEY") && env.get("MAKE_PUBLICKEY"))) {
throw new Error("MakeAPI Config setting invalid or missing!");
}
// Initialize make client so it is available to other modules
require("./lib/makeapi")({
apiURL: env.get( "MAKE_ENDPOINT" ),
apiURL: env.get("MAKE_ENDPOINT"),
hawk: {
key: env.get( "MAKE_PRIVATEKEY" ),
id: env.get( "MAKE_PUBLICKEY" ),
key: env.get("MAKE_PRIVATEKEY"),
id: env.get("MAKE_PUBLICKEY"),
algorithm: "sha256"
}
});
var routes = require("./routes");
nunjucksEnv.express( app );
app.disable( "x-powered-by" );
nunjucksEnv.express(app);
app.disable("x-powered-by");
app.use( express.logger( NODE_ENV === "development" ? "dev" : "" ) );
if ( !!env.get( "FORCE_SSL" ) ) {
app.use( helmet.hsts() );
app.enable( "trust proxy" );
app.use(express.logger(NODE_ENV === "development" ? "dev" : ""));
if ( !! env.get("FORCE_SSL")) {
app.use(helmet.hsts());
app.enable("trust proxy");
}
/**
* Crash isolation and error handling, logging
*/
if ( env.get( "GRAYLOG_HOST" ) ) {
GLOBAL.graylogHost = env.get( "GRAYLOG_HOST" );
GLOBAL.graylogFacility = env.get( "GRAYLOG_FACILITY" );
require( "graylog" );
if (env.get("GRAYLOG_HOST")) {
GLOBAL.graylogHost = env.get("GRAYLOG_HOST");
GLOBAL.graylogFacility = env.get("GRAYLOG_FACILITY");
require("graylog");
}
function reportError( error, isFatal ) {
function reportError(error, isFatal) {
try {
var severity = isFatal ? "CRASH" : "ERROR";
console.error( severity + ": " + error.stack );
if ( !GLOBAL.graylogHost ) {
console.error(severity + ": " + error.stack);
if (!GLOBAL.graylogHost) {
return;
}
log( "[" + severity + "] webmaker.org failure.",
error.message,
{
log("[" + severity + "] webmaker.org failure.",
error.message, {
level: isFatal ? LOG_CRIT : LOG_ERR,
stack: error.stack,
_fullStack: error.stack
}
);
} catch( err ) {
console.error( "Internal Error: unable to report error to graylog, err=" + err );
} catch (err) {
console.error("Internal Error: unable to report error to graylog, err=" + err);
}
}
app.use( function( req, res, next ) {
app.use(function (req, res, next) {
var guard = domain.create();
guard.add( req );
guard.add( res );
guard.add(req);
guard.add(res);
// Safely run a function in error isolation
function isolate( fn ) {
function isolate(fn) {
try {
fn();
} catch( e ) {
console.error( 'Internal error isolating shutdown sequence: ' + e );
} catch (e) {
console.error('Internal error isolating shutdown sequence: ' + e);
}
}
guard.on( 'error', function( err ) {
guard.on('error', function (err) {
try {
// Make sure we close down within 15 seconds
var killtimer = setTimeout( function() {
process.exit( 1 );
var killtimer = setTimeout(function () {
process.exit(1);
}, 15000);
// But don't keep the process open just for that!
killtimer.unref();
// Try and report this crash to graylog
reportError( err, true );
reportError(err, true);
// Try and shutdown the server, cluster worker
isolate(function() {
isolate(function () {
server.close();
if ( cluster.worker ) {
if (cluster.worker) {
cluster.worker.disconnect();
}
});
// Try sending a pretty 500 to the user
isolate(function() {
isolate(function () {
if (res._headerSent || res.finished) {
return;
}
res.statusCode = 500;
res.render( 'error.html', { message: err.message, code: err.status });
res.render('error.html', {
message: err.message,
code: err.status
});
});
guard.dispose();
} catch( err2 ) {
console.error( 'Internal error shutting down domain: ', err2.stack );
} catch (err2) {
console.error('Internal error shutting down domain: ', err2.stack);
}
process.exit( 1 );
process.exit(1);
});
guard.run( next );
guard.run(next);
});
app.use( express.compress() );
app.use( express.static( WWW_ROOT ));
app.use( "/bower", express.static( path.join(__dirname, "bower_components" )));
app.use(express.compress());
app.use(express.static(WWW_ROOT));
app.use("/bower", express.static(path.join(__dirname, "bower_components")));
// List of supported languages - Please add them here in an alphabetical order
var listDropdownLang = env.get( "SUPPORTED_LANGS" ),
// We create another array based on listDropdownLang to use it in the i18n.middleware
// supported_language which will be modified from the i18n mapping function
supportedLanguages = listDropdownLang.slice(0);
var listDropdownLang = env.get("SUPPORTED_LANGS"),
// We create another array based on listDropdownLang to use it in the i18n.middleware
// supported_language which will be modified from the i18n mapping function
supportedLanguages = listDropdownLang.slice(0);
// Setup locales with i18n
app.use( i18n.middleware({
app.use(i18n.middleware({
supported_languages: supportedLanguages,
default_lang: "en-US",
mappings: env.get( "LANG_MAPPINGS" ),
translation_directory: path.resolve( __dirname, "locale" )
mappings: env.get("LANG_MAPPINGS"),
translation_directory: path.resolve(__dirname, "locale")
}));
app.use( express.json() );
app.use( express.urlencoded() );
app.use( express.cookieParser() );
app.use( express.cookieSession({
app.use(express.json());
app.use(express.urlencoded());
app.use(express.cookieParser());
app.use(express.cookieSession({
key: "webmaker.sid",
secret: env.get( "SESSION_SECRET" ),
secret: env.get("SESSION_SECRET"),
cookie: {
maxAge: 2678400000, // 31 days. Persona saves session data for 1 month
secure: !!env.get( "FORCE_SSL" )
secure: !! env.get("FORCE_SSL")
},
proxy: true
}));
app.use( express.csrf() );
app.use(express.csrf());
app.locals({
makeEndpoint: env.get( "MAKE_ENDPOINT" ),
personaSSO: env.get( "AUDIENCE" ),
loginAPI: env.get( "LOGIN" ),
ga_account: env.get( "GA_ACCOUNT" ),
ga_domain: env.get( "GA_DOMAIN" ),
makeEndpoint: env.get("MAKE_ENDPOINT"),
personaSSO: env.get("AUDIENCE"),
loginAPI: env.get("LOGIN"),
ga_account: env.get("GA_ACCOUNT"),
ga_domain: env.get("GA_DOMAIN"),
supportedLanguages: supportedLanguages,
listDropdownLang: listDropdownLang,
PROFILE_URL: env.get( "PROFILE_URL" )
PROFILE_URL: env.get("PROFILE_URL")
});
app.use(function( req, res, next ) {
app.use(function (req, res, next) {
res.locals({
email: req.session.email || '',
username: req.session.username|| '',
username: req.session.username || '',
makerID: req.session.id || '',
csrf: req.session._csrf,
navigation: navigation,
@ -225,11 +230,11 @@ app.use(function( req, res, next ) {
next();
});
require( "./lib/events" ).init( app, nunjucksEnv, __dirname );
require("./lib/events").init(app, nunjucksEnv, __dirname);
var optimize = NODE_ENV !== "development",
tmpDir = path.join( require( "os" ).tmpDir(), "mozilla.webmaker.org" );
app.use( lessMiddleWare({
tmpDir = path.join(require("os").tmpDir(), "mozilla.webmaker.org");
app.use(lessMiddleWare({
once: optimize,
debug: !optimize,
dest: tmpDir,
@ -238,139 +243,143 @@ app.use( lessMiddleWare({
yuicompress: optimize,
optimization: optimize ? 0 : 2
}));
app.use( express.static( tmpDir ) );
app.use(express.static(tmpDir));
// Nunjucks
// This just uses nunjucks-dev for now -- middleware to handle compiling templates in progress
app.use( "/views", express.static(path.join( __dirname, "views" ) ) );
app.use("/views", express.static(path.join(__dirname, "views")));
app.use( app.router );
app.use(app.router);
// We've run out of known routes, 404
app.use( function( req, res, next ) {
res.status( 404 );
res.render( 'error.html', { code: 404 });
app.use(function (req, res, next) {
res.status(404);
res.render('error.html', {
code: 404
});
});
// Final error-handling middleware
app.use( function( err, req, res, next) {
app.use(function (err, req, res, next) {
err.status = err.status || 500;
reportError( err );
res.status( err.status );
res.render( 'error.html', { message: err.message, code: err.status });
reportError(err);
res.status(err.status);
res.render('error.html', {
message: err.message,
code: err.status
});
});
require( "./lib/loginapi" )( app, {
loginURL: env.get( "LOGINAPI" ),
audience: env.get( "AUDIENCE" ),
verifierURI: env.get( "PERSONA_VERIFIER_URI" )
require("./lib/loginapi")(app, {
loginURL: env.get("LOGINAPI"),
audience: env.get("AUDIENCE"),
verifierURI: env.get("PERSONA_VERIFIER_URI")
});
var middleware = require( "./lib/middleware" );
var middleware = require("./lib/middleware");
// ROUTES
var useNewHomePage = env.get("NEW_HOME_PAGE");
var teachTheWebRoute;
app.get( "/healthcheck", routes.api.healthcheck );
app.get("/healthcheck", routes.api.healthcheck);
if ( useNewHomePage ) {
if (useNewHomePage) {
teachTheWebRoute = "/";
} else {
teachTheWebRoute = "/teachtheweb";
app.get( "/", routes.gallery({
app.get("/", routes.gallery({
layout: "index",
prefix: "p"
}));
}
app.get( "/gallery", routes.gallery({
app.get("/gallery", routes.gallery({
layout: "index",
prefix: "p"
}));
app.get( teachTheWebRoute, routes.gallery({
app.get(teachTheWebRoute, routes.gallery({
layout: "teachtheweb",
prefix: "frontpage",
limit: 10
}));
app.get( "/editor", middleware.checkAdmin, routes.gallery({
app.get("/editor", middleware.checkAdmin, routes.gallery({
page: "editor"
}));
app.get( "/about", routes.page( "about" ) );
app.get( "/teach", routes.gallery({
app.get("/about", routes.page("about"));
app.get("/teach", routes.gallery({
layout: "teach",
prefix: "teach"
}));
app.get( "/starter-makes", routes.gallery({
app.get("/starter-makes", routes.gallery({
layout: "starterMakes",
prefix: "template",
limit: 20
}));
app.get("/party", routes.page("party"));
app.get("/tools", routes.page("tools"));
app.get("/teach-templates", routes.page("teach-templates"));
app.get("/mentor", routes.page("mentor"));
app.get("/getinvolved", routes.page("getinvolved"));
app.get("/event-guides", routes.page("event-guides"));
app.get("/search", routes.search);
app.get("/feedback", routes.page("feedback"));
app.get("/standard", routes.page("standard"));
app.get("/standard/exploring", routes.page("standard-exploring"));
app.get("/standard/building", routes.page("standard-building"));
app.get("/standard/connecting", routes.page("standard-connecting"));
app.get("/style-guide", routes.page("style-guide"));
app.get( "/party", routes.page( "party" ) );
app.get( "/tools", routes.page( "tools" ) );
app.get( "/teach-templates", routes.page( "teach-templates") );
app.get( "/mentor", routes.page( "mentor" ) );
app.get( "/getinvolved", routes.page( "getinvolved" ) );
app.get( "/event-guides", routes.page( "event-guides" ) );
app.get( "/search", routes.search );
app.get( "/feedback", routes.page( "feedback" ) );
app.get( "/standard", routes.page( "standard" ) );
app.get( "/standard/exploring", routes.page( "standard-exploring" ) );
app.get( "/standard/building", routes.page( "standard-building" ) );
app.get( "/standard/connecting", routes.page( "standard-connecting" ) );
app.get( "/style-guide", routes.page( "style-guide" ) );
app.get( "/details", routes.details );
app.get("/details", routes.details);
// Old
app.get( "/details/:id", function(req,res) {
app.get("/details/:id", function (req, res) {
res.redirect("/details?id=" + req.params.id);
});
app.get( "/me", routes.me );
app.get("/me", routes.me);
// Old
app.get( "/myprojects", routes.me );
app.post( "/remove", routes.remove );
app.post( "/like", routes.like.like );
app.post( "/unlike", routes.like.unlike );
app.get("/myprojects", routes.me);
app.post("/remove", routes.remove);
app.post("/like", routes.like.like);
app.post("/unlike", routes.like.unlike);
// Account
app.get( "/login", routes.user.login );
app.get( "/new", routes.user.newaccount );
app.get("/login", routes.user.login);
app.get("/new", routes.user.newaccount);
app.get( "/t/:tag", routes.tag );
app.get( "/u/:user", routes.usersearch );
app.get("/t/:tag", routes.tag);
app.get("/u/:user", routes.usersearch);
app.get( "/terms", routes.page( "terms" ) );
app.get( "/privacy", routes.page( "privacy" ) );
app.get("/terms", routes.page("terms"));
app.get("/privacy", routes.page("privacy"));
var personaHostname = env.get( "PERSONA_HOSTNAME", "https://login.persona.org" );
var personaHostname = env.get("PERSONA_HOSTNAME", "https://login.persona.org");
app.get( "/sso/include.js", routes.includejs( env.get( "HOSTNAME" ) ) );
app.get( "/sso/include.html", routes.include({
app.get("/sso/include.js", routes.includejs(env.get("HOSTNAME")));
app.get("/sso/include.html", routes.include({
personaHostname: personaHostname
}));
app.get( "/sso/include-transparent.html", routes.include({
app.get("/sso/include-transparent.html", routes.include({
personaHostname: personaHostname,
transparent: "transparent"
}));
app.get( "/sitemap.xml", function(req, res){
res.type( "xml" );
app.get("/sitemap.xml", function (req, res) {
res.type("xml");
res.render("sitemap.xml");
});
// Localized Strings
app.get( "/strings/:lang?", i18n.stringsRoute( "en-US" ) );
app.get("/strings/:lang?", i18n.stringsRoute("en-US"));
// BrowserID SSO realm file
app.get( "/.well-known/browserid-realm", routes.browserid( env.get( "SSO_DOMAINS" )));
app.get("/.well-known/browserid-realm", routes.browserid(env.get("SSO_DOMAINS")));
/**
* Legacy Webmaker Redirects
*/
require( "./routes/redirect" )( app );
require("./routes/redirect")(app);
server = app.listen( env.get( "PORT" ), function() {
console.log( "Server listening ( http://localhost:%d )", env.get( "PORT" ));
server = app.listen(env.get("PORT"), function () {
console.log("Server listening ( http://localhost:%d )", env.get("PORT"));
});

Просмотреть файл

@ -1,3 +1,3 @@
module.exports = function(app, options) {
module.exports = function (app, options) {
module.exports = require("webmaker-loginapi")(app, options);
};

Просмотреть файл

@ -4,29 +4,29 @@ var toolURL = {
"application/x-x-ray-goggles": "https://goggles.webmaker.org"
};
module.exports = function(options) {
module.exports = function (options) {
var moment = require("moment");
var makeClient = require("makeapi-client")(options);
function generateGravatar(hash) {
var DEFAULT_AVATAR = "https%3A%2F%2Fstuff.webmaker.org%2Favatars%2Fwebmaker-avatar-44x44.png",
DEFAULT_SIZE = 44;
return "https://secure.gravatar.com/avatar/" + hash + "?s="+ DEFAULT_SIZE +"&d=" + DEFAULT_AVATAR;
DEFAULT_SIZE = 44;
return "https://secure.gravatar.com/avatar/" + hash + "?s=" + DEFAULT_SIZE + "&d=" + DEFAULT_AVATAR;
}
// Moment.js default language is 'en'. This function will override
// the default language globally on the coming request for the homepage
makeClient.setLang = function(lang) {
makeClient.setLang = function (lang) {
moment.lang(lang);
};
// Given a prefix for an app tag (e.g. "webmaker:p-") sort an array of makes based on that tag
// The tag must be of the format "prefix-1", "prefix-2", etc.
makeClient.sortByPriority = function(prefix, data) {
makeClient.sortByPriority = function (prefix, data) {
var sortedData = [],
duplicates = [],
priorityIndex,
regex = new RegExp("^" + prefix + "(\\d+)$");
duplicates = [],
priorityIndex,
regex = new RegExp("^" + prefix + "(\\d+)$");
function extractStickyPriority(tags) {
var res;
@ -38,10 +38,10 @@ module.exports = function(options) {
}
}
for (var i=0; i<data.length; i++) {
for (var i = 0; i < data.length; i++) {
priorityIndex = extractStickyPriority(data[i].appTags);
data[i].index = priorityIndex;
if ( sortedData[priorityIndex - 1] ) {
if (sortedData[priorityIndex - 1]) {
duplicates.push("Duplicate found for " + prefix + priorityIndex);
} else {
sortedData[priorityIndex - 1] = data[i];
@ -54,17 +54,17 @@ module.exports = function(options) {
};
};
makeClient.process = function(callback, id) {
makeClient.then(function(err, data, totalHits) {
makeClient.process = function (callback, id) {
makeClient.then(function (err, data, totalHits) {
if (err) {
return callback(err);
}
if (!Array.isArray(data) ) {
if (!Array.isArray(data)) {
return callback("There was no data returned");
}
data.map(function( make ){
data.map(function (make) {
// Set the tool
make.tool = make.contentType.replace(/application\/x\-/g, "");
@ -87,8 +87,8 @@ module.exports = function(options) {
make.level = "advanced";
}
if ( id ) {
make.hasBeenLiked = make.likes.some(function( like ) {
if (id) {
make.hasBeenLiked = make.likes.some(function (like) {
return like.userId === +id;
});
}
@ -111,4 +111,3 @@ module.exports = function(options) {
module.exports = makeClient;
};

Просмотреть файл

@ -1,7 +1,7 @@
var loginAPI = require("./loginapi");
module.exports.checkAdmin = function(req, res, next) {
loginAPI.getUserByEmail(req.session.email, function(err, user){
module.exports.checkAdmin = function (req, res, next) {
loginAPI.getUserByEmail(req.session.email, function (err, user) {
if (err || !user || !user.isAdmin) {
return next(new Error("Admin access only"));
}

Просмотреть файл

@ -41,6 +41,7 @@
"devDependencies": {
"grunt": "0.4.1",
"grunt-recess": "0.3.3",
"grunt-contrib-jshint": "0.4.3"
"grunt-contrib-jshint": "0.7.1",
"grunt-jsbeautifier": "0.2.2"
}
}

Просмотреть файл

@ -4,7 +4,7 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
var DEFAULT_LIMIT = 12;
var lang = $('html').attr('lang');
moment.lang(localized.langToMomentJSLang(lang));
var Gallery = function(options) {
var Gallery = function (options) {
var self = this;
options = options || {};
@ -17,11 +17,11 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
options.defaultSearch = options.defaultSearch || 'webmaker:recommended';
var banner = document.querySelector(options.banner),
mainGallery = document.querySelector(options.mainGallery),
$mainGallery = $(mainGallery),
$loadMore = $('.load-more'),
$loading = $('.loading-cat'),
$emptyMessage = $('.no-makes-found');
mainGallery = document.querySelector(options.mainGallery),
$mainGallery = $(mainGallery),
$loadMore = $('.load-more'),
$loading = $('.loading-cat'),
$emptyMessage = $('.no-makes-found');
var limit = $mainGallery.data('limit') || DEFAULT_LIMIT;
var totalHits = $mainGallery.data('total-hits');
@ -36,8 +36,8 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
// MakeAPI
var make = new Make({
apiURL: options.makeUrl
}),
apiURL: options.makeUrl
}),
searchOptions = {
limit: limit,
tags: options.defaultSearch,
@ -52,7 +52,7 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
});
// Which items are large on the front page?
var FRONTPAGE_LARGE = [2,3];
var FRONTPAGE_LARGE = [2, 3];
// Nunjucks
// Todo - nunjucks middleware
@ -90,8 +90,8 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
e.preventDefault();
e.stopPropagation();
var $this = $(this),
makeID = $this.data("make-id"),
method;
makeID = $this.data("make-id"),
method;
if ($this.hasClass("icon-heart")) {
method = "/unlike";
@ -101,10 +101,10 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
$.post(method, {
makeID: makeID,
_csrf: $("meta[name='X-CSRF-Token']").attr("content")
}, function(res) {
}, function (res) {
var newLen = res.likes.length,
$count = $this.parent().parent().find(".like-count"),
$text = $this.parent().parent().find(".like-text");
$count = $this.parent().parent().find(".like-count"),
$text = $this.parent().parent().find(".like-text");
$this.toggleClass("icon-heart icon-heart-empty");
$count.html(newLen);
@ -115,10 +115,10 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
} else {
$text.html(localized.get("Like-n"));
}
}).fail(function(res) {
}).fail(function (res) {
if (res.status === 401) {
window.location.replace(window.location.protocol + "//" + window.location.host +
"/" + localized.getCurrentLang() + "/login");
"/" + localized.getCurrentLang() + "/login");
} else {
// already like/unliked, update UI to reflect.
$this.toggleClass("icon-heart icon-heart-empty");
@ -128,12 +128,12 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
function resultsCallback(err, data, total) {
var isStickySearch = (searchOptions.tagPrefix === options.stickyPrefix),
itemString = '',
frag = document.createElement('div'),
makerID = $("meta[name='maker-id']").attr("content"),
allItems,
i,
l;
itemString = '',
frag = document.createElement('div'),
makerID = $("meta[name='maker-id']").attr("content"),
allItems,
i,
l;
$loading.hide();
@ -178,9 +178,9 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
frag.innerHTML = itemString;
allItems = frag.querySelectorAll(options.itemSelector);
$(allItems)
.find(".make-like-toggle")
.off("click")
.on("click", likeClickCallback);
.find(".make-like-toggle")
.off("click")
.on("click", likeClickCallback);
$mainGallery.append(allItems);
packery.appended(allItems);
packery.layout();
@ -191,7 +191,7 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
self.searchOptions = searchOptions;
self.packery = packery;
self.make = make;
self.search = function(opts) {
self.search = function (opts) {
opts = opts || {};
if (opts.sticky) {
searchOptions.tagPrefix = options.stickyPrefix;
@ -210,14 +210,14 @@ define(['jquery', 'nunjucks', 'base/ui', 'moment', 'makeapi', 'localized'],
}
packery.layout();
localized.ready(function() {
localized.ready(function () {
$(".make-like-toggle")
.off("click")
.on("click", likeClickCallback);
.off("click")
.on("click", likeClickCallback);
});
// Set up load more
$loadMore.click(function() {
$loadMore.click(function () {
searchOptions.page++;
$loading.show();
self.search({

Просмотреть файл

@ -1,75 +1,75 @@
define( ["jquery", "text!html/ui-fragments.html" ], function( $, _fragments ) {
define(["jquery", "text!html/ui-fragments.html"], function ($, _fragments) {
"use strict";
var UI = {},
$fragments = $( document.createElement( "div" ) ).html( _fragments );
$fragments = $(document.createElement("div")).html(_fragments);
UI.select = function (select, fn) {
UI.select = function( select, fn ) {
$(".filter").removeClass("hide");
var $el = $( ".ui-select", $fragments ).clone( true ),
$toggleBtn = $el.find( ".icon" ),
$selectedEl = $el.find( ".ui-selected" ),
$menuContainer = $el.find( ".ui-select-menu" ),
$menu = $menuContainer.find( "ul" ),
$li = $menu.find( "li" );
var $el = $(".ui-select", $fragments).clone(true),
$toggleBtn = $el.find(".icon"),
$selectedEl = $el.find(".ui-selected"),
$menuContainer = $el.find(".ui-select-menu"),
$menu = $menuContainer.find("ul"),
$li = $menu.find("li");
var $select = $( select ),
$options = $( "option", select ),
id = $select.attr( "id" );
var $select = $(select),
$options = $("option", select),
id = $select.attr("id");
fn = fn || function() {};
fn = fn || function () {};
$options.each( function( i, option ) {
var val = $( option ).val(),
html = $( option ).html(),
$newLi = $li.clone();
$newLi.attr( "data-value", val );
$newLi.html( html );
if ( $( option ).attr( "selected" ) ) {
$newLi.attr( "data-selected", true);
$selectedEl.html( html );
$options.each(function (i, option) {
var val = $(option).val(),
html = $(option).html(),
$newLi = $li.clone();
$newLi.attr("data-value", val);
$newLi.html(html);
if ($(option).attr("selected")) {
$newLi.attr("data-selected", true);
$selectedEl.html(html);
}
$newLi.click( function() {
var $this = $( this );
$newLi.click(function () {
var $this = $(this);
$menu.find( "[data-selected]" ).removeAttr( "data-selected" );
$( this ).attr( "data-selected", true );
$selectedEl.text( html );
$menu.find("[data-selected]").removeAttr("data-selected");
$(this).attr("data-selected", true);
$selectedEl.text(html);
$menuContainer.hide();
fn( val );
$select.val( val );
fn(val);
$select.val(val);
});
$menu.append( $newLi );
$menu.append($newLi);
});
$selectedEl.click( function( e ) {
$selectedEl.click(function (e) {
$menuContainer.toggle();
});
$toggleBtn.click( function( e ) {
$toggleBtn.click(function (e) {
$menuContainer.toggle();
});
$el.attr( "id", id );
$select.removeAttr( "id" );
$el.attr("id", id);
$select.removeAttr("id");
$li.remove();
$el.insertAfter( $select );
$el.insertAfter($select);
$select.hide();
};
UI.pagination = function( page, total, limit, callback ) {
UI.pagination = function (page, total, limit, callback) {
var $pagination = $(".pagination"),
$ul = $pagination.find("ul"),
$_li = $("<li></li>"),
$li,
MAX_NUMS = 4,
totalPages = total ? Math.ceil(total/limit) : 0,
set = Math.floor((page-1)/MAX_NUMS),
startPage = set * MAX_NUMS + 1,
endPage = Math.min((set * MAX_NUMS) + MAX_NUMS, totalPages);
$ul = $pagination.find("ul"),
$_li = $("<li></li>"),
$li,
MAX_NUMS = 4,
totalPages = total ? Math.ceil(total / limit) : 0,
set = Math.floor((page - 1) / MAX_NUMS),
startPage = set * MAX_NUMS + 1,
endPage = Math.min((set * MAX_NUMS) + MAX_NUMS, totalPages);
if (totalPages > 1) {
$pagination.show();
@ -78,10 +78,10 @@ define( ["jquery", "text!html/ui-fragments.html" ], function( $, _fragments ) {
}
var $prevBtn = $_li.clone().html("<span class=\"icon-chevron-left\"></span>"),
$nextBtn = $_li.clone().html("<span class=\"icon-chevron-right\"></span>");
$nextBtn = $_li.clone().html("<span class=\"icon-chevron-right\"></span>");
function pageSearch(page) {
return function() {
return function () {
callback(page);
};
}
@ -89,7 +89,7 @@ define( ["jquery", "text!html/ui-fragments.html" ], function( $, _fragments ) {
$ul.empty();
// Show previous?
if ( page > 1 ) {
if (page > 1) {
$ul.append($prevBtn);
$prevBtn.click(pageSearch(page - 1));
}
@ -97,7 +97,7 @@ define( ["jquery", "text!html/ui-fragments.html" ], function( $, _fragments ) {
for (var i = startPage; i <= endPage; i++) {
$li = $_li.clone();
$li.text(i);
if (i === page ) {
if (i === page) {
$li.addClass("active");
}
$li.click(pageSearch(i));
@ -116,8 +116,6 @@ define( ["jquery", "text!html/ui-fragments.html" ], function( $, _fragments ) {
}
};
return UI;
});

Просмотреть файл

@ -1,18 +1,18 @@
requirejs.config({
baseDir:'/js',
baseDir: '/js',
paths: {
'text': '/bower/text/text',
'jquery': '/bower/jquery/jquery.min',
'jquery.powertip': '/js/lib/jquery.powertip',
'moment': '/bower/moment/min/moment+langs.min',
'social': '/js/lib/socialmedia',
'uri': '/js/lib/uri',
'tabzilla': 'https://www.mozilla.org/tabzilla/media/js/tabzilla',
'text': '/bower/text/text',
'jquery': '/bower/jquery/jquery.min',
'jquery.powertip': '/js/lib/jquery.powertip',
'moment': '/bower/moment/min/moment+langs.min',
'social': '/js/lib/socialmedia',
'uri': '/js/lib/uri',
'tabzilla': 'https://www.mozilla.org/tabzilla/media/js/tabzilla',
// XXX: window.__loginAPI gets templated in server-side in layout.html
'sso-ux': window.__loginAPI + '/js/sso-ux',
'nunjucks': '/bower/nunjucks/browser/nunjucks-dev',
'makeapi': '/bower/makeapi-client/src/make-api',
'localized': '/bower/webmaker-i18n/localized'
'sso-ux': window.__loginAPI + '/js/sso-ux',
'nunjucks': '/bower/nunjucks/browser/nunjucks-dev',
'makeapi': '/bower/makeapi-client/src/make-api',
'localized': '/bower/webmaker-i18n/localized'
},
shim: {
'tabzilla': ['jquery'],
@ -31,46 +31,46 @@ require([
'tabzilla',
'sso-ux'
], function ($, cta, Marquee, privacy, AnchorSlide, WebmakerUI, navigation) {
'use strict';
'use strict';
var $html = $('html, body');
var $window = $(window);
var $backToTop = $('.back-to-top');
var langSelector = document.querySelector("#lang-picker");
var $html = $('html, body');
var $window = $(window);
var $backToTop = $('.back-to-top');
var langSelector = document.querySelector("#lang-picker");
// Show and hide "Back To Top" trigger
$window.scroll(function() {
if ($window.scrollTop() > 100) {
$backToTop.addClass('addMore');
} else {
$backToTop.removeClass('addMore');
}
});
// Attach navigation UI
navigation();
// Generate CTA bar in footer
cta.attachToCTA();
// Create Anchor Sliders
$('a.anchor-slide').each(function () {
var anchorSlide = new AnchorSlide(this);
});
// Create Partner marquees
$('ul.sponsors').each(function () {
var marquee = new Marquee(this);
marquee.startRotation();
});
// URL redirector for language picker
WebmakerUI.langPicker(langSelector);
// Set up page-specific js
var pageJS = $('#require-js').data('page');
if (pageJS) {
require([pageJS]);
// Show and hide "Back To Top" trigger
$window.scroll(function () {
if ($window.scrollTop() > 100) {
$backToTop.addClass('addMore');
} else {
$backToTop.removeClass('addMore');
}
});
// Attach navigation UI
navigation();
// Generate CTA bar in footer
cta.attachToCTA();
// Create Anchor Sliders
$('a.anchor-slide').each(function () {
var anchorSlide = new AnchorSlide(this);
});
// Create Partner marquees
$('ul.sponsors').each(function () {
var marquee = new Marquee(this);
marquee.startRotation();
});
// URL redirector for language picker
WebmakerUI.langPicker(langSelector);
// Set up page-specific js
var pageJS = $('#require-js').data('page');
if (pageJS) {
require([pageJS]);
}
});

Просмотреть файл

@ -1,95 +1,95 @@
define(['jquery', 'social', 'localized'],
function ($, SocialMedia, localized) {
localized.ready(function() {
var social,
localized.ready(function () {
var social,
$body = $("body"),
$shareBtn = $( "#share-btn" ),
$shareContainer = $( "#share-container" ),
$shareBtn = $("#share-btn"),
$shareContainer = $("#share-container"),
$likeBtn = $(".make-like-toggle"),
$likeCount = $(".like-count"),
$likeText = $(".like-text"),
$notLoggedInMsg = $( ".not-logged-in" ),
googleBtn = document.getElementById( "google-btn" ),
twitterBtn = document.getElementById( "twitter-btn" ),
fbBtn = document.getElementById( "fb-btn" ),
$notLoggedInMsg = $(".not-logged-in"),
googleBtn = document.getElementById("google-btn"),
twitterBtn = document.getElementById("twitter-btn"),
fbBtn = document.getElementById("fb-btn"),
tool = $body.data("tool"),
url = $body.data("url");
var socialMessage = localized.get('DetailsShareTwitterMsg');
social = new SocialMedia({
message: socialMessage,
via: "webmaker"
});
var socialMessage = localized.get('DetailsShareTwitterMsg');
social = new SocialMedia({
message: socialMessage,
via: "webmaker"
});
function shareOnClick() {
social.hotLoad( twitterBtn, social.twitter, url );
social.hotLoad( googleBtn, social.google, url );
social.hotLoad( fbBtn, social.facebook, url );
$shareBtn.addClass( "hidden" );
$shareContainer.removeClass( "hidden" );
$shareBtn.off( "click", shareOnClick );
}
function openLogInWindow() {
window.open( "/login", "Log In" );
}
$shareBtn.on( "click", shareOnClick );
$notLoggedInMsg.on( "click", openLogInWindow );
$likeBtn.on( "click", function(e) {
if( e.target !== $likeBtn[0] ) {
return;
function shareOnClick() {
social.hotLoad(twitterBtn, social.twitter, url);
social.hotLoad(googleBtn, social.google, url);
social.hotLoad(fbBtn, social.facebook, url);
$shareBtn.addClass("hidden");
$shareContainer.removeClass("hidden");
$shareBtn.off("click", shareOnClick);
}
e.preventDefault();
function openLogInWindow() {
window.open("/login", "Log In");
}
var makeID = $likeBtn.data("make-id"),
$shareBtn.on("click", shareOnClick);
$notLoggedInMsg.on("click", openLogInWindow);
$likeBtn.on("click", function (e) {
if (e.target !== $likeBtn[0]) {
return;
}
e.preventDefault();
var makeID = $likeBtn.data("make-id"),
count,
method;
if( $likeBtn.hasClass( "icon-heart" ) ) {
method = "/unlike";
} else {
method = "/like";
}
if ($likeBtn.hasClass("icon-heart")) {
method = "/unlike";
} else {
method = "/like";
}
$.post(method, {
makeID: makeID,
_csrf: $("meta[name='X-CSRF-Token']").attr("content")
}, function(res) {
$.post(method, {
makeID: makeID,
_csrf: $("meta[name='X-CSRF-Token']").attr("content")
}, function (res) {
var newLen = res.likes.length;
$likeBtn.toggleClass("icon-heart icon-heart-empty");
$likeCount.html(newLen);
if (newLen === 0) {
$likeText.html(localized.get("Like-0"));
} else if ( newLen === 1) {
} else if (newLen === 1) {
$likeText.html(localized.get("Like-1"));
} else {
$likeText.html(localized.get("Like-n"));
}
}).fail(function(res) {
var timer;
}).fail(function (res) {
var timer;
function removeLogInMsg( e ) {
window.removeEventListener( "click", removeLogInMsg, false );
window.clearTimeout( timer );
$notLoggedInMsg.addClass( "hide" );
}
function removeLogInMsg(e) {
window.removeEventListener("click", removeLogInMsg, false);
window.clearTimeout(timer);
$notLoggedInMsg.addClass("hide");
}
if ( res.status === 401 ) {
$notLoggedInMsg.removeClass( "hide" );
timer = window.setTimeout( removeLogInMsg, 5000 );
window.addEventListener( "click", function( e ) {
if ( e.target === $notLoggedInMsg.find( "a" )[0] ) {
return true;
}
removeLogInMsg();
}, false );
}
if (res.status === 401) {
$notLoggedInMsg.removeClass("hide");
timer = window.setTimeout(removeLogInMsg, 5000);
window.addEventListener("click", function (e) {
if (e.target === $notLoggedInMsg.find("a")[0]) {
return true;
}
removeLogInMsg();
}, false);
}
});
});
});
});
});
//blue

Просмотреть файл

@ -1,8 +1,8 @@
define(["jquery", "localized", "nunjucks", "base/ui", "moment", "uri", "makeapi"],
function ($, localized, nunjucks, UI, moment, URI, Make) {
"use strict";
"use strict";
var MAKE_VIEW = "make-templates/make-admin-search.html",
var MAKE_VIEW = "make-templates/make-admin-search.html",
MAKE_URL = $("body").data("endpoint"),
LIMIT = 12,
STICKY_PREFIX = "webmaker:teach-",
@ -12,7 +12,7 @@ define(["jquery", "localized", "nunjucks", "base/ui", "moment", "uri", "makeapi"
$emptyMessage = $(".no-makes-found"),
stampBanner = document.querySelector(".stamp"),
mainGallery = document.querySelector(".main-gallery"),
$mainGallery= $(mainGallery),
$mainGallery = $(mainGallery),
$header = $("header"),
$sidebar = $(".admin-sidebar "),
$adminSearch = $("#admin-search-input"),
@ -21,147 +21,150 @@ define(["jquery", "localized", "nunjucks", "base/ui", "moment", "uri", "makeapi"
lastQuery,
makeAPIUrl = $("body").data("endpoint"),
makeAPIUrlHost = URI.parse(makeAPIUrl).host,
queryKeys = URI.parse( window.location.href ).queryKey,
queryKeys = URI.parse(window.location.href).queryKey,
lang = $('html').attr('lang');
moment.lang(localized.langToMomentJSLang(lang));
moment.lang(localized.langToMomentJSLang(lang));
nunjucks.env = new nunjucks.Environment(new nunjucks.HttpLoader("/views", true));
nunjucks.env = new nunjucks.Environment(new nunjucks.HttpLoader("/views", true));
// Making a custom filter to use it for the client-side l10n
// Using this filter will help reduce the number of adding
// variables to the global nunjucks variable.
// The usage will be "{{ "some string" | gettext }}"
nunjucks.env.addFilter('gettext', function (data) {
return localized.get(data);
});
// Making a custom filter to use it for the client-side l10n
// Using this filter will help reduce the number of adding
// variables to the global nunjucks variable.
// The usage will be "{{ "some string" | gettext }}"
nunjucks.env.addFilter('gettext', function (data) {
return localized.get(data);
});
// Set up packery
var packery = new Packery(mainGallery, {
itemSelector: "div.make",
gutter: ".gutter-sizer"
});
// Set up packery
var packery = new Packery(mainGallery, {
itemSelector: "div.make",
gutter: ".gutter-sizer"
});
packery.on("layoutComplete", function() {
$(".packery-hide", $mainGallery).removeClass("packery-hide");
});
packery.on("layoutComplete", function () {
$(".packery-hide", $mainGallery).removeClass("packery-hide");
});
var searchPackery = new Packery(searchResults, {
itemSelector: "div.make",
gutter: 10
});
var searchPackery = new Packery(searchResults, {
itemSelector: "div.make",
gutter: 10
});
// Create make client for teach, set up default options
var make = new Make({
apiURL: MAKE_URL
});
// Create make client for teach, set up default options
var make = new Make({apiURL: MAKE_URL});
function generateGravatar(hash) {
// TODO: Combine with makeapi-webmaker.js into universal module
var DEFAULT_AVATAR = "https%3A%2F%2Fstuff.webmaker.org%2Favatars%2Fwebmaker-avatar-44x44.png",
function generateGravatar(hash) {
// TODO: Combine with makeapi-webmaker.js into universal module
var DEFAULT_AVATAR = "https%3A%2F%2Fstuff.webmaker.org%2Favatars%2Fwebmaker-avatar-44x44.png",
DEFAULT_SIZE = 44;
return "https://secure.gravatar.com/avatar/" + hash + "?s="+ DEFAULT_SIZE +"&d=" + DEFAULT_AVATAR;
}
function resultsCallback(err, data, total) {
var oldMakes = searchResults.querySelectorAll(".make");
var showingString = total ? ("Showing pg. " + lastQuery.page+ " of " + total ) : "No";
if (oldMakes.length) {
searchPackery.remove(oldMakes);
return "https://secure.gravatar.com/avatar/" + hash + "?s=" + DEFAULT_SIZE + "&d=" + DEFAULT_AVATAR;
}
$loading.hide();
$(".search-summary").html( showingString + " results for " + lastQuery.field + " = " + lastQuery.value + " on " + "<a href=\"" + makeAPIUrl + "/admin\">" + makeAPIUrlHost + "</a>");
UI.pagination(lastQuery.page, total, LIMIT, function( page ) {
lastQuery.page = page;
function resultsCallback(err, data, total) {
var oldMakes = searchResults.querySelectorAll(".make");
var showingString = total ? ("Showing pg. " + lastQuery.page + " of " + total) : "No";
if (oldMakes.length) {
searchPackery.remove(oldMakes);
}
$loading.hide();
$(".search-summary").html(showingString + " results for " + lastQuery.field + " = " + lastQuery.value + " on " + "<a href=\"" + makeAPIUrl + "/admin\">" + makeAPIUrlHost + "</a>");
UI.pagination(lastQuery.page, total, LIMIT, function (page) {
lastQuery.page = page;
doSearch(lastQuery);
});
if (err || !data.length) {
return;
}
for (var i = 0; i < data.length; i++) {
if (data[i]) {
data[i].avatar = generateGravatar(data[i].emailHash);
data[i].updatedAt = moment(data[i].updatedAt).fromNow();
data[i].createdAt = moment(data[i].createdAt).fromNow();
data[i].remixurl = data[i].url + "/remix";
var $item = $($.parseHTML(nunjucks.env.render(MAKE_VIEW, {
make: data[i]
}))[0]);
$searchResults.prepend($item);
searchPackery.appended($item[0]);
}
}
searchPackery.layout();
}
if (stampBanner) {
packery.stamp(stampBanner);
packery.layout();
}
var scrollTop = $sidebar.offset().top;
$(window).scroll(function (e) {
var windowTop = $(window).scrollTop();
if (windowTop > scrollTop) {
$sidebar.css("top", "0");
} else {
$sidebar.css("top", scrollTop - windowTop);
}
});
function doSearch(options) {
options = options || {};
options.field = options.field || $(".search-type label.active").data("field");
options.value = options.value || $adminSearch.val();
options.limit = options.limit || LIMIT;
options.sortByField = options.sortByField || "createdAt";
options.sortByDirection = options.sortByDirection || "desc";
options.page = options.page || 1;
lastQuery = options;
var searchQuery = {
limit: options.limit,
sortByField: [options.sortByField, options.sortByDirection],
page: options.page
};
searchQuery[options.field] = options.value;
localized.ready(function () {
make.find(searchQuery).then(resultsCallback);
});
}
//Choosing field
$(".search-type label").click(function (e) {
$(".search-type label.active").removeClass("active");
$(this).addClass("active");
doSearch({
field: $(this).data("field")
});
});
UI.select("#filter", function (val) {
lastQuery.sortByField = val;
lastQuery.page = 1;
doSearch(lastQuery);
});
if (err || !data.length) {
return;
}
for (var i=0; i<data.length; i++) {
if (data[i]) {
data[i].avatar = generateGravatar(data[i].emailHash);
data[i].updatedAt = moment( data[i].updatedAt ).fromNow();
data[i].createdAt = moment( data[i].createdAt ).fromNow();
data[i].remixurl = data[i].url + "/remix";
var $item = $($.parseHTML(nunjucks.env.render(MAKE_VIEW, {make: data[i]}))[0]);
$searchResults.prepend($item);
searchPackery.appended($item[0]);
UI.select("#prefix-select", function (val) {
queryKeys.prefix = val;
window.location.search = $.param(queryKeys);
});
UI.select("#layout-select", function (val) {
queryKeys.layout = val;
window.location.search = $.param(queryKeys);
});
$adminSearch.bind("keypress", function (e) {
var code = (e.keyCode ? e.keyCode : e.which);
if (code === 13) { //Enter keycode
doSearch();
}
}
searchPackery.layout();
}
if (stampBanner) {
packery.stamp(stampBanner);
packery.layout();
}
var scrollTop = $sidebar.offset().top;
$(window).scroll(function(e) {
var windowTop = $(window).scrollTop();
if (windowTop > scrollTop) {
$sidebar.css("top", "0");
} else {
$sidebar.css("top", scrollTop - windowTop);
}
});
function doSearch(options){
options = options || {};
options.field = options.field || $(".search-type label.active").data("field");
options.value = options.value || $adminSearch.val();
options.limit = options.limit || LIMIT;
options.sortByField = options.sortByField || "createdAt";
options.sortByDirection = options.sortByDirection || "desc";
options.page = options.page || 1;
lastQuery = options;
var searchQuery = {
limit: options.limit,
sortByField: [options.sortByField, options.sortByDirection],
page: options.page
};
searchQuery[options.field] = options.value;
localized.ready(function(){
make.find(searchQuery).then(resultsCallback);
});
}
//Choosing field
$(".search-type label").click(function(e) {
$(".search-type label.active").removeClass("active");
$(this).addClass("active");
doSearch({
field: $(this).data("field")
});
doSearch();
});
UI.select("#filter", function(val) {
lastQuery.sortByField = val;
lastQuery.page = 1;
doSearch(lastQuery);
});
UI.select("#prefix-select", function(val) {
queryKeys.prefix = val;
window.location.search = $.param(queryKeys);
});
UI.select("#layout-select", function(val) {
queryKeys.layout = val;
window.location.search = $.param(queryKeys);
});
$adminSearch.bind("keypress", function(e) {
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13) { //Enter keycode
doSearch();
}
});
doSearch();
});

Просмотреть файл

@ -1,5 +1,5 @@
require(['jquery', 'base/ui', 'base/gallery'],
function($, UI, Gallery) {
function ($, UI, Gallery) {
'use strict';
var gallery = new Gallery({
@ -10,39 +10,39 @@ require(['jquery', 'base/ui', 'base/gallery'],
});
// Hide the banner if the user already exists
navigator.idSSO.app.onlogin = function(loggedInUser, displayName) {
navigator.idSSO.app.onlogin = function (loggedInUser, displayName) {
$('#banner-join').hide();
gallery.packery.layout();
};
UI.select('#search-filter', function(val) {
UI.select('#search-filter', function (val) {
var makes = document.querySelectorAll('.make');
switch (val) {
case 'featured':
gallery.searchOptions.tags = {
tags: ['webmaker:featured']
};
gallery.searchOptions.sortByField = ['createdAt', 'desc'];
delete gallery.searchOptions.contentType;
break;
case 'featured':
gallery.searchOptions.tags = {
tags: ['webmaker:featured']
};
gallery.searchOptions.sortByField = ['createdAt', 'desc'];
delete gallery.searchOptions.contentType;
break;
case 'popcorn':
gallery.searchOptions.tags = {
tags: ['webmaker:featured']
};
gallery.searchOptions.sortByField = ['createdAt', 'desc'];
gallery.searchOptions.contentType = 'application/x-popcorn';
break;
case 'popcorn':
gallery.searchOptions.tags = {
tags: ['webmaker:featured']
};
gallery.searchOptions.sortByField = ['createdAt', 'desc'];
gallery.searchOptions.contentType = 'application/x-popcorn';
break;
case 'thimble':
gallery.searchOptions.tags = {
tags: ['webmaker:featured']
};
gallery.searchOptions.sortByField = ['createdAt', 'desc'];
gallery.searchOptions.contentType = 'application/x-thimble';
break;
case 'thimble':
gallery.searchOptions.tags = {
tags: ['webmaker:featured']
};
gallery.searchOptions.sortByField = ['createdAt', 'desc'];
gallery.searchOptions.contentType = 'application/x-thimble';
break;
}
// Reset and set to page 1

Просмотреть файл

@ -1,91 +1,87 @@
define(['jquery', 'uri', 'base/ui', 'localized'],
function ($, URI, UI, localized) {
'use strict';
'use strict';
localized.ready(function() {
var $body = $("body"),
localized.ready(function () {
var $body = $("body"),
$makes = $(".make"),
$deleteBtn = $(".delete-btn"),
mainGallery = $(".main-gallery")[0],
totalHits,
LIMIT,
queryKeys = URI.parse( window.location.href ).queryKey,
queryKeys = URI.parse(window.location.href).queryKey,
BASE_WIDTH = 240,
GUTTER = 20,
packery,
page;
// Are we inside thimble or popcorn?
var inApp = $body.hasClass("popcorn") || $body.hasClass("thimble");
// Are we inside thimble or popcorn?
var inApp = $body.hasClass("popcorn") || $body.hasClass("thimble");
// If the user is not logged in yet,
// refresh the page once they are.
// This properly generates server side project data
// for apps using my makes.
if (inApp && !$("meta[name='persona-email']").attr("content")) {
navigator.idSSO.app = {
onlogin: function(){
window.location.replace(window.location);
}
};
}
// Do we have any makes?
if (!$makes.length) {
return;
}
// Set up scrollable container
if (inApp) {
$(".webmaker-outer-wrapper").css("width", ( ( BASE_WIDTH + GUTTER ) * $makes.length + GUTTER * 2 ) + "px");
$("html").css("overflow-y", "hidden");
}
// Or, set up packery if we are on webmaker.org
if (!inApp) {
packery = new Packery( mainGallery, {
itemSelector: 'div.make',
gutter: '.gutter-sizer',
transitionDuration: '0.2'
});
}
// Set up the delete buttons
$deleteBtn.on( "click", function(e) {
e.preventDefault();
var $this = $(this),
makeID = $this.data("make-id");
if(confirm(localized.get("Are you sure you want to delete this make?"))) {
$.post("/remove", {
makeID: makeID,
_csrf: $("meta[name='X-CSRF-Token']").attr("content")
}, function(res) {
if ( res.deletedAt ) {
if (!inApp) {
packery.remove($this.closest(".make")[0]);
packery.layout();
} else {
$this.closest(".make").remove();
}
} else {
console.log(res);
// If the user is not logged in yet,
// refresh the page once they are.
// This properly generates server side project data
// for apps using my makes.
if (inApp && !$("meta[name='persona-email']").attr("content")) {
navigator.idSSO.app = {
onlogin: function () {
window.location.replace(window.location);
}
}).fail( function(res) {
console.log(res.responseText);
};
}
// Do we have any makes?
if (!$makes.length) {
return;
}
// Set up scrollable container
if (inApp) {
$(".webmaker-outer-wrapper").css("width", ((BASE_WIDTH + GUTTER) * $makes.length + GUTTER * 2) + "px");
$("html").css("overflow-y", "hidden");
}
// Or, set up packery if we are on webmaker.org
if (!inApp) {
packery = new Packery(mainGallery, {
itemSelector: 'div.make',
gutter: '.gutter-sizer',
transitionDuration: '0.2'
});
}
// Set up the delete buttons
$deleteBtn.on("click", function (e) {
e.preventDefault();
var $this = $(this),
makeID = $this.data("make-id");
if (window.confirm(localized.get("Are you sure you want to delete this make?"))) {
$.post("/remove", {
makeID: makeID,
_csrf: $("meta[name='X-CSRF-Token']").attr("content")
}, function (res) {
if (res.deletedAt) {
if (!inApp) {
packery.remove($this.closest(".make")[0]);
packery.layout();
} else {
$this.closest(".make").remove();
}
}
});
}
});
page = queryKeys.page ? parseInt(queryKeys.page, 10) : 1;
if (mainGallery) {
totalHits = mainGallery.getAttribute("data-total-hits");
LIMIT = mainGallery.getAttribute("data-limit");
UI.pagination(page, totalHits, LIMIT, function (page) {
queryKeys.page = page;
window.location.search = $.param(queryKeys);
});
}
});
page = queryKeys.page ? parseInt(queryKeys.page, 10) : 1;
if ( mainGallery ) {
totalHits = mainGallery.getAttribute("data-total-hits");
LIMIT = mainGallery.getAttribute("data-limit");
UI.pagination( page, totalHits, LIMIT, function( page ) {
queryKeys.page = page;
window.location.search = $.param( queryKeys );
});
}
});
});

Просмотреть файл

@ -1,27 +1,27 @@
define(["jquery"],
function ($) {
"use strict";
var $carouselContainer = $(".commitment-carousel-items"),
$carouselItems = $( ".commitment-carousel-item", $carouselContainer ),
"use strict";
var $carouselContainer = $(".commitment-carousel-items"),
$carouselItems = $(".commitment-carousel-item", $carouselContainer),
count = 0,
max = $carouselItems.length;
function rotateCarousel() {
var next = count + 1;
if ( count >= max ) {
count = 0;
}
if ( next >= max) {
next = 0;
}
var $item = $(".commitment-carousel-item:nth-child(" + count + ")", $carouselContainer ),
$nextItem = $(".commitment-carousel-item:nth-child(" + next + ")", $carouselContainer );
function rotateCarousel() {
var next = count + 1;
if (count >= max) {
count = 0;
}
if (next >= max) {
next = 0;
}
var $item = $(".commitment-carousel-item:nth-child(" + count + ")", $carouselContainer),
$nextItem = $(".commitment-carousel-item:nth-child(" + next + ")", $carouselContainer);
$item.fadeOut(function(){
$nextItem.fadeIn();
});
count = count + 1;
}
$item.fadeOut(function () {
$nextItem.fadeIn();
});
count = count + 1;
}
setInterval( rotateCarousel, 5000 );
});
setInterval(rotateCarousel, 5000);
});

Просмотреть файл

@ -1,9 +1,9 @@
define(["jquery", "uri", "base/ui" ],
define(["jquery", "uri", "base/ui"],
function ($, URI, UI) {
"use strict";
"use strict";
var query = $(".search-poster").attr( "data-query"),
queryKeys = URI.parse( window.location.href ).queryKey,
var query = $(".search-poster").attr("data-query"),
queryKeys = URI.parse(window.location.href).queryKey,
$searchPoster = $(".search-poster"),
$searchField = $("#search-field"),
$searchFilter = $("#search-type"),
@ -16,64 +16,66 @@ define(["jquery", "uri", "base/ui" ],
packery,
page;
function onKeyDown() {
$("html, body").animate({ scrollTop: 0 }, 200 );
$searchPoster.addClass( "focus");
$searchField.off("keydown", onKeyDown);
}
function onKeyDown() {
$("html, body").animate({
scrollTop: 0
}, 200);
$searchPoster.addClass("focus");
$searchField.off("keydown", onKeyDown);
}
// Show the big green UI
if ($searchPoster.hasClass("focus") && query) {
$searchField.val(query.replace(/,/g,", "));
onKeyDown();
} else {
$searchField.on("keydown", onKeyDown);
}
// Show the big green UI
if ($searchPoster.hasClass("focus") && query) {
$searchField.val(query.replace(/,/g, ", "));
onKeyDown();
} else {
$searchField.on("keydown", onKeyDown);
}
// Setup packery
packery = new Packery( mainGallery, {
itemSelector: "div.make",
gutter: ".gutter-sizer",
transitionDuration: "0.2"
});
// Change what kind of search
$searchFilter.find("li").click( function(){
var $this = $(this),
type = $this.attr("data-value");
$searchFilter.find("[name=type]").val( type );
$searchFilter.find("[data-selected] > span").attr("class", "icon-" + type);
$searchFilter.find(".ui-on").removeClass("ui-on");
$this.addClass("ui-on");
});
$forkBtns.click( function(e) {
e.stopPropagation();
});
$userNameLinks.click( function(e) {
e.stopPropagation();
queryKeys.page = 1;
queryKeys.type = "user";
queryKeys.q = this.getAttribute("data-username");
window.location.search = $.param(queryKeys);
});
page = queryKeys.page ? parseInt(queryKeys.page, 10) : 1;
if ( mainGallery ) {
totalHits = mainGallery.getAttribute("data-total-hits");
LIMIT = mainGallery.getAttribute("data-limit");
UI.pagination( page, totalHits, LIMIT, function( page ) {
queryKeys.page = page;
if (queryKeys.q) {
queryKeys.q = decodeURIComponent(queryKeys.q);
}
window.location.search = $.param( queryKeys );
// Setup packery
packery = new Packery(mainGallery, {
itemSelector: "div.make",
gutter: ".gutter-sizer",
transitionDuration: "0.2"
});
}
});
// Change what kind of search
$searchFilter.find("li").click(function () {
var $this = $(this),
type = $this.attr("data-value");
$searchFilter.find("[name=type]").val(type);
$searchFilter.find("[data-selected] > span").attr("class", "icon-" + type);
$searchFilter.find(".ui-on").removeClass("ui-on");
$this.addClass("ui-on");
});
$forkBtns.click(function (e) {
e.stopPropagation();
});
$userNameLinks.click(function (e) {
e.stopPropagation();
queryKeys.page = 1;
queryKeys.type = "user";
queryKeys.q = this.getAttribute("data-username");
window.location.search = $.param(queryKeys);
});
page = queryKeys.page ? parseInt(queryKeys.page, 10) : 1;
if (mainGallery) {
totalHits = mainGallery.getAttribute("data-total-hits");
LIMIT = mainGallery.getAttribute("data-limit");
UI.pagination(page, totalHits, LIMIT, function (page) {
queryKeys.page = page;
if (queryKeys.q) {
queryKeys.q = decodeURIComponent(queryKeys.q);
}
window.location.search = $.param(queryKeys);
});
}
});

Просмотреть файл

@ -1,11 +1,13 @@
define(['jquery', 'base/ui', 'base/gallery'],
function ($, UI, Gallery) {
'use strict';
'use strict';
var gallery = new Gallery({
makeView: 'make-starter-make.html',
stickyPrefix: 'webmaker:template-',
defaultSearch: {
tags: ['webmaker:template']
}
});
var gallery = new Gallery({
makeView: 'make-starter-make.html',
stickyPrefix: 'webmaker:template-',
defaultSearch: { tags: [ 'webmaker:template' ] }
});
});

Просмотреть файл

@ -1,12 +1,14 @@
define(['jquery', 'base/ui', 'base/gallery'],
function ($, UI, Gallery) {
'use strict';
'use strict';
var gallery = new Gallery({
banner: '#banner-teach',
makeView: 'make-teach.html',
stickyPrefix: 'webmaker:teach-',
defaultSearch: {
tags: ['webmaker:teach']
}
});
var gallery = new Gallery({
banner: '#banner-teach',
makeView: 'make-teach.html',
stickyPrefix: 'webmaker:teach-',
defaultSearch: { tags: [ 'webmaker:teach' ] }
});
});

Просмотреть файл

@ -1,86 +1,88 @@
define(['jquery'],
function ($) {
var $window = $(window);
var $toggleButtonContainer = $('.mentor-story-nav');
var $toggleButtons = $('.mentor-story-nav a');
var totalStories = $('.mentor-story-nav a').length;
var $nextButton = $('.go-forward');
var $backButton = $('.go-back');
var $articles = $('.mentor-stories article');
var $posters = $('.poster-image-container > div');
var $hiddenScroll = $('.hidden-scroll');
var gallery = document.querySelector('.make-now-templates');
var hideScrollTimeout;
var $window = $(window);
var $toggleButtonContainer = $('.mentor-story-nav');
var $toggleButtons = $('.mentor-story-nav a');
var totalStories = $('.mentor-story-nav a').length;
var $nextButton = $('.go-forward');
var $backButton = $('.go-back');
var $articles = $('.mentor-stories article');
var $posters = $('.poster-image-container > div');
var $hiddenScroll = $('.hidden-scroll');
var gallery = document.querySelector('.make-now-templates');
var hideScrollTimeout;
function changeStory(storyId) {
$toggleButtons.removeClass('active');
$('.mentor-story-nav a[data-id="' + storyId +'"]').addClass('active');
$('.mentor-stories article.active').removeClass('active');
$('.poster-image-container > div.active').removeClass('active');
$('#story-' + storyId).addClass('active');
$('#poster-' + storyId).addClass('active');
function changeStory(storyId) {
$toggleButtons.removeClass('active');
$('.mentor-story-nav a[data-id="' + storyId + '"]').addClass('active');
$('.mentor-stories article.active').removeClass('active');
$('.poster-image-container > div.active').removeClass('active');
$('#story-' + storyId).addClass('active');
$('#poster-' + storyId).addClass('active');
var currentIndex = $('.mentor-story-nav a').index( $('.mentor-story-nav a.active') );
if (currentIndex === 0) {
$backButton.hide();
} else {
$backButton.show();
var currentIndex = $('.mentor-story-nav a').index($('.mentor-story-nav a.active'));
if (currentIndex === 0) {
$backButton.hide();
} else {
$backButton.show();
}
if (currentIndex >= totalStories - 1) {
$nextButton.hide();
} else {
$nextButton.show();
}
}
if (currentIndex >= totalStories - 1) {
$nextButton.hide();
} else {
$nextButton.show();
function getStoryByNumber(n) {
// Convert 0 index > selector nth-child, which starts with one
n = n + 1;
return $toggleButtonContainer.find('a:nth-child(' + n + ')').attr('data-id');
}
}
function getStoryByNumber(n) {
// Convert 0 index > selector nth-child, which starts with one
n = n + 1;
return $toggleButtonContainer.find('a:nth-child('+ n +')').attr('data-id');
}
function hideScroll() {
$hiddenScroll.addClass('hidden-scroll');
}
function onScroll() {
$hiddenScroll.removeClass('hidden-scroll');
if (hideScrollTimeout) {
clearTimeout(hideScrollTimeout);
function hideScroll() {
$hiddenScroll.addClass('hidden-scroll');
}
hideScrollTimeout = setTimeout(hideScroll, 1000);
}
$window.on('scroll', onScroll);
function onScroll() {
$hiddenScroll.removeClass('hidden-scroll');
if (hideScrollTimeout) {
clearTimeout(hideScrollTimeout);
}
hideScrollTimeout = setTimeout(hideScroll, 1000);
}
$('#make-something').click( function() {
$('html, body').animate({ scrollTop: $('.make-something-now').offset().top }, 1000);
$window.on('scroll', onScroll);
$('#make-something').click(function () {
$('html, body').animate({
scrollTop: $('.make-something-now').offset().top
}, 1000);
});
var packery = new Packery(gallery, {
itemSelector: '.make-now-templates > article',
gutter: '.gutter-make-now'
});
$toggleButtons.on('click', function () {
var storyId = this.getAttribute('data-id');
changeStory(storyId);
});
$nextButton.on('click', function () {
var currentIndex = $('.mentor-story-nav a').index($('.mentor-story-nav a.active'));
var storyId = getStoryByNumber(currentIndex + 1);
changeStory(storyId);
});
$backButton.on('click', function () {
var currentIndex = $('.mentor-story-nav a').index($('.mentor-story-nav a.active'));
var storyId = getStoryByNumber(currentIndex - 1);
changeStory(storyId);
});
var randomStoryIndex = Math.floor(Math.random() * totalStories) - 1;
changeStory(getStoryByNumber(randomStoryIndex));
});
var packery = new Packery(gallery, {
itemSelector: '.make-now-templates > article',
gutter: '.gutter-make-now'
});
$toggleButtons.on('click', function() {
var storyId = this.getAttribute('data-id');
changeStory(storyId);
});
$nextButton.on('click', function() {
var currentIndex = $('.mentor-story-nav a').index( $('.mentor-story-nav a.active') );
var storyId = getStoryByNumber(currentIndex + 1);
changeStory(storyId);
});
$backButton.on('click', function() {
var currentIndex = $('.mentor-story-nav a').index( $('.mentor-story-nav a.active') );
var storyId = getStoryByNumber(currentIndex - 1);
changeStory(storyId);
});
var randomStoryIndex = Math.floor( Math.random() * totalStories ) - 1;
changeStory(getStoryByNumber(randomStoryIndex));
});

Просмотреть файл

@ -1,21 +1,20 @@
define(['jquery', '/bower/webmaker-ui/ui.js', 'sso-ux'],
function($, WebmakerUI, localized) {
"use strict";
var lang = $('html').attr('lang');
function ($, WebmakerUI, localized) {
"use strict";
var lang = $('html').attr('lang');
navigator.idSSO.app.onlogin = function(user) {
if( document.referrer.indexOf( 'events' ) !== -1 ){
window.location = "/" + lang + "/events";
}
else {
window.location = "/" + lang;
}
};
navigator.idSSO.app.onnewuser = function(){
window.location = "/" + lang + "/new";
};
navigator.idSSO.app.onlogin = function (user) {
if (document.referrer.indexOf('events') !== -1) {
window.location = "/" + lang + "/events";
} else {
window.location = "/" + lang;
}
};
navigator.idSSO.app.onnewuser = function () {
window.location = "/" + lang + "/new";
};
var langSelector = document.querySelector("#lang-picker");
// URL redirector for language picker
WebmakerUI.langPicker(langSelector);
});
var langSelector = document.querySelector("#lang-picker");
// URL redirector for language picker
WebmakerUI.langPicker(langSelector);
});

Просмотреть файл

@ -1,65 +1,65 @@
define(['jquery', 'sso-ux'],
function($) {
"use strict";
var $formFrag = $("#sso_create");
var $mailSignUp = $('#bsd');
var $usernameInput = $("#claim-input");
var $errorContainer = $("#error-container");
var csrf = $("meta[name='X-CSRF-Token']").attr("content");
var email = $("meta[name='persona-email']").attr("content");
var AUDIENCE = $("meta[name='audience']").attr("content");
var loginURL = $("meta[name='login-url']").attr("content");
function ($) {
"use strict";
var $formFrag = $("#sso_create");
var $mailSignUp = $('#bsd');
var $usernameInput = $("#claim-input");
var $errorContainer = $("#error-container");
var csrf = $("meta[name='X-CSRF-Token']").attr("content");
var email = $("meta[name='persona-email']").attr("content");
var AUDIENCE = $("meta[name='audience']").attr("content");
var loginURL = $("meta[name='login-url']").attr("content");
// Redirect if the user has an account;
navigator.idSSO.app.onlogin = function(user) {
window.location = "/";
};
// Redirect if the user has an account;
navigator.idSSO.app.onlogin = function (user) {
window.location = "/";
};
// Prevent default dropdown
navigator.idSSO.app.onnewuser = function() {};
// Prevent default dropdown
navigator.idSSO.app.onnewuser = function () {};
$formFrag.submit(function (data) {
if ($mailSignUp.is(':checked')) {
$.ajax({
type: 'POST',
url: 'https://sendto.mozilla.org/page/s/webmaker',
data: {
email: $usernameInput.val(),
'custom-1216': 1
},
success: function (resp) {
return true;
},
error: function (resp) {
return false;
}
});
}
$formFrag.submit( function(data) {
if( $mailSignUp.is(':checked') ) {
$.ajax({
type: 'POST',
url: 'https://sendto.mozilla.org/page/s/webmaker',
type: "POST",
url: loginURL + "/user",
headers: {
"X-CSRF-Token": csrf
},
dataType: "json",
data: {
email: $usernameInput.val(),
'custom-1216': 1
"_id": email,
"email": email,
"username": $usernameInput.val()
},
success: function(resp) {
return true;
success: function (resp) {
window.location = "/";
},
error: function(resp) {
error: function (resp) {
var error = JSON.parse(resp.responseText);
if (error.error.code === 11000) {
$errorContainer.text("Sorry, the username " + $usernameInput.val() + " is taken!");
$usernameInput.val("");
}
return false;
}
});
}
$.ajax({
type: "POST",
url: loginURL + "/user",
headers: {
"X-CSRF-Token": csrf
},
dataType: "json",
data: {
"_id": email,
"email": email,
"username": $usernameInput.val()
},
success: function(resp) {
window.location = "/";
},
error: function(resp) {
var error = JSON.parse(resp.responseText);
if(error.error.code === 11000 ) {
$errorContainer.text("Sorry, the username "+ $usernameInput.val() + " is taken!");
$usernameInput.val("");
}
return false;
}
return false;
});
return false;
});
});

Просмотреть файл

@ -1,6 +1,6 @@
var version = require( "../../package" ).version;
var version = require("../../package").version;
module.exports = function( req, res ) {
module.exports = function (req, res) {
res.send({
"http": "okay",
"version": version

Просмотреть файл

@ -1,4 +1,4 @@
module.exports = function(domains) {
module.exports = function (domains) {
var realmResponse;
if (domains) {
@ -7,7 +7,7 @@ module.exports = function(domains) {
};
}
return function(req, res, next) {
return function (req, res, next) {
if (!realmResponse) {
return res.send(404);
}

Просмотреть файл

@ -1,72 +1,73 @@
module.exports = function(req, res) {
module.exports = function (req, res) {
var MAX_REMIXES = 5;
var make = require("../lib/makeapi");
function renderError(message) {
return res.render("details.html", {error:message});
return res.render("details.html", {
error: message
});
}
// Use a URL in the querystring or an ID
var searchOptions = {},
searchCriteria;
if ( req.query.id ) {
searchCriteria;
if (req.query.id) {
searchCriteria = "id";
searchOptions.id = req.query.id;
} else if ( req.query.url ) {
} else if (req.query.url) {
searchCriteria = "url";
searchOptions.url = decodeURIComponent( req.query.url );
searchOptions.url = decodeURIComponent(req.query.url);
} else {
return renderError("No URL or ID was passed");
}
make.setLang(req.localeInfo.momentLang);
make.find(searchOptions).process( function( err, data ) {
if ( err ) {
make.find(searchOptions).process(function (err, data) {
if (err) {
return renderError("Looks like there is a problem with the make API");
}
if ( data && !data.length ) {
if (data && !data.length) {
return renderError("No make was found :(");
}
var makeData = data[ 0 ];
var makeData = data[0];
// Prep remixes, max of 10
makeData.remixes( function( err, remixData, totalHits ) {
if ( err ) {
makeData.remixes(function (err, remixData, totalHits) {
if (err) {
return renderError("Looks like there is a problem with the make API");
}
makeData.remixList = [];
for ( var i = 0; i < Math.min( remixData.length, MAX_REMIXES ); i++ ) {
for (var i = 0; i < Math.min(remixData.length, MAX_REMIXES); i++) {
makeData.remixList.push({
url: remixData[ i ].url,
username: remixData[ i ].username
url: remixData[i].url,
username: remixData[i].username
});
}
if ( totalHits === 1 ) {
if (totalHits === 1) {
makeData.remixCount = "1 remix";
} else {
makeData.remixCount = totalHits + " remixes";
}
// Prep original source
if ( makeData.remixedFrom ) {
make[ searchCriteria ]( makeData.remixedFrom ).then( function( err, remixedFromData ) {
if ( err ) {
return renderError( "Looks like there is a problem with the make API" );
if (makeData.remixedFrom) {
make[searchCriteria](makeData.remixedFrom).then(function (err, remixedFromData) {
if (err) {
return renderError("Looks like there is a problem with the make API");
}
if ( remixedFromData && remixedFromData.length ) {
if (remixedFromData && remixedFromData.length) {
makeData.remixedFromData = {};
makeData.remixedFromData.url = remixedFromData[ 0 ].url;
makeData.remixedFromData.username = remixedFromData[ 0 ].username;
makeData.remixedFromData.url = remixedFromData[0].url;
makeData.remixedFromData.username = remixedFromData[0].username;
}
res.render( "details.html", makeData );
res.render("details.html", makeData);
});
} else {
res.render( "details.html", makeData );
res.render("details.html", makeData);
}
});
});
}, req.session.id || '');
};

Просмотреть файл

@ -1,127 +1,129 @@
var async = require("async"),
make = require("../lib/makeapi");
make = require("../lib/makeapi");
module.exports = function(options) {
return function(req, res, next) {
var DEFAULT_PREFIX = "p",
DEFAULT_LAYOUT = "index",
DEFAULT_STICKY_LIMIT = 24, // Larger to account for possible duplicates
DEFAULT_LIMIT = 12,
layouts = {
index: {
template: "make-flip.html",
tags: ['webmaker:recommended'],
process: function(makes) {
if( makes[2] ) {
makes[2].size = "large";
}
if( makes[3] ) {
makes[3].size = "large";
}
return makes;
}
},
teach: {
template: "make-teach.html",
tags: ['webmaker:teach']
},
starterMakes: {
template: "make-starter-make.html",
tags: ["webmaker:template"]
},
teachtheweb: {
tags: ["webmaker:frontpage"]
module.exports = function (options) {
return function (req, res, next) {
var DEFAULT_PREFIX = "p",
DEFAULT_LAYOUT = "index",
DEFAULT_STICKY_LIMIT = 24, // Larger to account for possible duplicates
DEFAULT_LIMIT = 12,
layouts = {
index: {
template: "make-flip.html",
tags: ['webmaker:recommended'],
process: function (makes) {
if (makes[2]) {
makes[2].size = "large";
}
};
if (makes[3]) {
makes[3].size = "large";
}
return makes;
}
},
teach: {
template: "make-teach.html",
tags: ['webmaker:teach']
},
starterMakes: {
template: "make-starter-make.html",
tags: ["webmaker:template"]
},
teachtheweb: {
tags: ["webmaker:frontpage"]
}
};
options = options || {};
options = options || {};
// prefix: Set the app-tag prefix for our intial layout settings
var prefix = options.prefix || (req.query.prefix || DEFAULT_PREFIX).toString(),
stickyPrefix = "webmaker:" + (prefix + "-");
// prefix: Set the app-tag prefix for our intial layout settings
var prefix = options.prefix || (req.query.prefix || DEFAULT_PREFIX).toString(),
stickyPrefix = "webmaker:" + (prefix + "-");
// layout: Choose a layout - should it look like the home or teach page?
// Sets the processing function and template piece
var layoutName = options.layout || (req.query.layout || DEFAULT_LAYOUT).toString(),
layout = layouts[layoutName] || layouts[DEFAULT_LAYOUT];
layout.name = layoutName;
// layout: Choose a layout - should it look like the home or teach page?
// Sets the processing function and template piece
var layoutName = options.layout || (req.query.layout || DEFAULT_LAYOUT).toString(),
layout = layouts[layoutName] || layouts[DEFAULT_LAYOUT];
layout.name = layoutName;
// page: This is for rendering the view.
var page = options.page || layoutName;
// page: This is for rendering the view.
var page = options.page || layoutName;
// limit
var limit = options.limit || DEFAULT_LIMIT;
var stickyLimit = options.limit ? options.limit * 2 : DEFAULT_STICKY_LIMIT;
var totalHitCount = [];
// limit
var limit = options.limit || DEFAULT_LIMIT;
var stickyLimit = options.limit ? options.limit * 2 : DEFAULT_STICKY_LIMIT;
var totalHitCount = [];
function getMakes(options, callback) {
make.setLang(req.localeInfo.momentLang);
make
.find(options)
.process( function( err, data, totalHits ) {
totalHitCount.push(totalHits);
callback(err, data);
}, req.session.id || '');
function getMakes(options, callback) {
make.setLang(req.localeInfo.momentLang);
make
.find(options)
.process(function (err, data, totalHits) {
totalHitCount.push(totalHits);
callback(err, data);
}, req.session.id || '');
}
var stickyOptions = {
tagPrefix: stickyPrefix,
limit: stickyLimit,
sortByField: ["createdAt", "desc"]
};
var normalOptions = {
tagPrefix: [stickyPrefix, true], // true = NOT search
tags: {
tags: layout.tags
},
limit: limit,
sortByField: ["createdAt", "desc"]
};
async.map([stickyOptions, normalOptions], getMakes, function (err, data) {
var sticky = [],
warnings = [],
normal,
all = [],
sortByPriorityResults,
totalNormalHits;
if (err) {
return next(err);
}
var stickyOptions = {
tagPrefix: stickyPrefix,
limit: stickyLimit,
sortByField: ["createdAt", "desc"]
};
if (data[0].length) {
sortByPriorityResults = make.sortByPriority(stickyPrefix, data[0]);
sticky = sortByPriorityResults.results;
warnings = warnings.concat(sortByPriorityResults.errors);
}
var normalOptions = {
tagPrefix: [stickyPrefix, true], // true = NOT search
tags: { tags: layout.tags },
// Send warning messages to editor about missing stickies
for (var i = 0; i < limit; i++) {
if (!sticky[i]) {
warnings.push("No sticky set for " + stickyPrefix + (i + 1));
}
}
totalNormalHits = totalHitCount[1]; // We stored totals for sticky and normal
normal = data[1];
all = sticky.concat(normal);
// Is there a special processing function for this layout?
if (layout.process) {
all = layout.process(all);
}
res.render(page + ".html", {
makes: all,
totalHits: totalNormalHits,
limit: limit,
sortByField: ["createdAt", "desc"]
};
async.map([stickyOptions, normalOptions], getMakes, function(err, data) {
var sticky = [],
warnings = [],
normal,
all = [],
sortByPriorityResults,
totalNormalHits;
if (err) {
return next(err);
}
if (data[0].length) {
sortByPriorityResults = make.sortByPriority(stickyPrefix, data[0]);
sticky = sortByPriorityResults.results;
warnings = warnings.concat(sortByPriorityResults.errors);
}
// Send warning messages to editor about missing stickies
for(i=0; i<limit; i++) {
if(!sticky[i]) {
warnings.push("No sticky set for " + stickyPrefix + (i+1));
}
}
totalNormalHits = totalHitCount[1]; // We stored totals for sticky and normal
normal = data[1];
all = sticky.concat(normal);
// Is there a special processing function for this layout?
if (layout.process) {
all = layout.process(all);
}
res.render( page + ".html", {
makes: all,
totalHits: totalNormalHits,
limit: limit,
warnings: warnings,
page: page,
prefix: prefix,
layout: layout.name,
template: layout.template,
isAdmin: req.isAdmin || false
});
warnings: warnings,
page: page,
prefix: prefix,
layout: layout.name,
template: layout.template,
isAdmin: req.isAdmin || false
});
};
});
};
};

Просмотреть файл

@ -5,31 +5,31 @@ module.exports = {
browserid: require("./browserid"),
details: require("./details"),
gallery: require("./gallery"),
include: function( options ) {
return function( req, res ) {
res.render( "sso/include.html", options);
include: function (options) {
return function (req, res) {
res.render("sso/include.html", options);
};
},
includejs: function( hostname ) {
return function( req, res ) {
res.set( "Content-Type", "application/javascript;charset=utf-8" );
res.render( "sso/include.js", {
includejs: function (hostname) {
return function (req, res) {
res.set("Content-Type", "application/javascript;charset=utf-8");
res.render("sso/include.js", {
HOSTNAME: hostname
});
};
},
me: require("./me"),
page: function( view ) {
page: function (view) {
return require("./page")(view);
},
remove: require("./remove"),
like: require("./like")(),
search: require("./search"),
tag: function( req, res ) {
res.redirect( "/" + req.localeInfo.lang + "/search?type=tags&q=" + req.params.tag );
tag: function (req, res) {
res.redirect("/" + req.localeInfo.lang + "/search?type=tags&q=" + req.params.tag);
},
user: require("./user"),
usersearch: function( req, res ) {
res.redirect( "/" + req.localeInfo.lang + "/search?type=user&q=" + req.params.user );
usersearch: function (req, res) {
res.redirect("/" + req.localeInfo.lang + "/search?type=user&q=" + req.params.user);
}
};

Просмотреть файл

@ -1,34 +1,34 @@
module.exports = function() {
var make = require( "../lib/makeapi" );
module.exports = function () {
var make = require("../lib/makeapi");
return {
like: function( req, res ) {
like: function (req, res) {
var id = req.body.makeID,
maker = req.session.username;
maker = req.session.username;
if ( maker ) {
make.like( id, maker, function( err, data ) {
if ( err || !data ) {
return res.send( 400, err || "Something went wrong." );
if (maker) {
make.like(id, maker, function (err, data) {
if (err || !data) {
return res.send(400, err || "Something went wrong.");
}
res.json( 200, data );
res.json(200, data);
});
} else {
res.send( 401, "Not Logged In" );
res.send(401, "Not Logged In");
}
},
unlike: function( req, res ) {
unlike: function (req, res) {
var id = req.body.makeID,
maker = req.session.username;
maker = req.session.username;
if ( maker ) {
make.unlike( id, maker, function( err, data ) {
if ( err || !data ) {
return res.send( 400, err || "something went wrong" );
if (maker) {
make.unlike(id, maker, function (err, data) {
if (err || !data) {
return res.send(400, err || "something went wrong");
}
res.json( 200, data );
res.json(200, data);
});
} else {
res.send( 401, "Not Logged In" );
res.send(401, "Not Logged In");
}
}
};

Просмотреть файл

@ -1,16 +1,16 @@
module.exports = function( req, res ) {
module.exports = function (req, res) {
var make = require("../lib/makeapi"),
username = req.session.username,
page = req.query.page || 1,
app = req.query.app,
options = {},
limit = 50;
username = req.session.username,
page = req.query.page || 1,
app = req.query.app,
options = {},
limit = 50;
// MakeAPI doesn't handle undefined being passed for user. To
// prevent the MakeAPI error showing when no signed in user accesses the page
// I'm checking here first.
if ( !username ) {
res.render( "me.html", {
if (!username) {
res.render("me.html", {
page: "me",
view: app || "webmaker"
});
@ -19,29 +19,29 @@ module.exports = function( req, res ) {
// Set up search options
options.user = username;
if ( app ) {
if (app) {
options.contentType = "application/x-" + app;
}
make.setLang(req.localeInfo.momentLang);
make.find( options )
.limit( limit )
.sortByField( "updatedAt", "desc" )
.page( page )
.process( function( err, data, totalHits ) {
if ( err ) {
return res.send( err );
}
make.find(options)
.limit(limit)
.sortByField("updatedAt", "desc")
.page(page)
.process(function (err, data, totalHits) {
if (err) {
return res.send(err);
}
res.render( "me.html", {
makes: data || [],
page: "me",
pagination: page,
view: app || "webmaker",
totalHits: totalHits,
limit: limit,
showPagination: ( totalHits > limit ),
username: username
res.render("me.html", {
makes: data || [],
page: "me",
pagination: page,
view: app || "webmaker",
totalHits: totalHits,
limit: limit,
showPagination: (totalHits > limit),
username: username
});
});
});
};

Просмотреть файл

@ -1,6 +1,6 @@
module.exports = function( view ) {
return function( req, res ) {
res.render( view + ".html", {
module.exports = function (view) {
return function (req, res) {
res.render(view + ".html", {
page: view
});
};

Просмотреть файл

@ -1,69 +1,67 @@
module.exports = function( app ) {
module.exports = function (app) {
var redirectMap = [
{
route: "/",
paths: [
"/projects",
"/projects/:id",
"/support",
"/videos",
"/hall-of-fame",
"/ITU",
"/ITU/*"
]
}, {
route: "/tools",
paths: [
"/tools/x-ray-goggles",
"/tools/x-ray-goggles/install"
]
}, {
route: "/party",
paths: [
"/partners"
]
}, {
// Switch to SSL after Bug 883370 lands.
route: "http://blog.webmaker.org",
paths: [
"/news"
]
}, {
route: "/teach",
paths: [
"/network",
"/kits",
"/kit-prototypes"
]
}, {
route: "/getinvolved",
paths: [
"/build",
"/get-involved"
]
}, {
route: "/mentor",
paths: [
"/connect"
]
}, {
route: "/event-guides",
paths: [
"/guides"
]
}, {
route: "https://support.mozilla.org/kb/translate-webmaker",
paths: [
"/translate"
]
}
];
var redirectMap = [{
route: "/",
paths: [
"/projects",
"/projects/:id",
"/support",
"/videos",
"/hall-of-fame",
"/ITU",
"/ITU/*"
]
}, {
route: "/tools",
paths: [
"/tools/x-ray-goggles",
"/tools/x-ray-goggles/install"
]
}, {
route: "/party",
paths: [
"/partners"
]
}, {
// Switch to SSL after Bug 883370 lands.
route: "http://blog.webmaker.org",
paths: [
"/news"
]
}, {
route: "/teach",
paths: [
"/network",
"/kits",
"/kit-prototypes"
]
}, {
route: "/getinvolved",
paths: [
"/build",
"/get-involved"
]
}, {
route: "/mentor",
paths: [
"/connect"
]
}, {
route: "/event-guides",
paths: [
"/guides"
]
}, {
route: "https://support.mozilla.org/kb/translate-webmaker",
paths: [
"/translate"
]
}];
redirectMap.forEach(function( redirect ) {
redirect.paths.forEach(function( legacyRoute ) {
app.get( legacyRoute, function( req, res ){
res.redirect( 301, redirect.route );
redirectMap.forEach(function (redirect) {
redirect.paths.forEach(function (legacyRoute) {
app.get(legacyRoute, function (req, res) {
res.redirect(301, redirect.route);
});
});
});

Просмотреть файл

@ -1,29 +1,28 @@
module.exports = function( req, res ) {
module.exports = function (req, res) {
var make = require("../lib/makeapi");
var id = req.body.makeID;
make.id( id ).then( function( err, data ) {
if ( err ) {
return res.send( err );
make.id(id).then(function (err, data) {
if (err) {
return res.send(err);
}
if ( data && !data.length ) {
return res.send( "Sorry, we couldn't find a make with that id!" );
if (data && !data.length) {
return res.send("Sorry, we couldn't find a make with that id!");
}
var username = data[0].username;
if ( username === req.session.username ) {
make.remove( id, function( err, data ) {
if ( err ) {
res.send( err );
if (username === req.session.username) {
make.remove(id, function (err, data) {
if (err) {
res.send(err);
} else {
res.json( data );
res.json(data);
}
});
}
else {
res.send( "Sorry, looks like you don't have permission to delete this make :(" );
} else {
res.send("Sorry, looks like you don't have permission to delete this make :(");
}
});
};

Просмотреть файл

@ -1,98 +1,98 @@
module.exports = function(req, res) {
module.exports = function (req, res) {
var make = require("../lib/makeapi"),
querystring = require("querystring");
querystring = require("querystring");
var DEFAULT_TYPE = "tags",
DEFAULT_QUERY = "webmaker:featured",
VALID_TYPES = [
"all",
"tags",
"title",
"user",
"description"
],
VALID_CONTENT_TYPES = [
"application/x-thimble",
"application/x-popcorn"
];
DEFAULT_QUERY = "webmaker:featured",
VALID_TYPES = [
"all",
"tags",
"title",
"user",
"description"
],
VALID_CONTENT_TYPES = [
"application/x-thimble",
"application/x-popcorn"
];
var type = ( req.query.type || DEFAULT_TYPE ).toString(),
contentType = ( req.query.contentType || '' ).toString(),
sortByField = ( req.query.sortByField || "createdAt" ).toString(),
sortByOrder = ( req.query.order || "desc" ).toString(),
page = ( req.query.page || 1 ).toString(),
setToAll = !( req.query.type || req.query.q ||
req.query.contentType || req.query.sortByField ||
req.query.order || req.query.page ),
options = {},
query,
hideNamespace = false;
var type = (req.query.type || DEFAULT_TYPE).toString(),
contentType = (req.query.contentType || '').toString(),
sortByField = (req.query.sortByField || "createdAt").toString(),
sortByOrder = (req.query.order || "desc").toString(),
page = (req.query.page || 1).toString(),
setToAll = !(req.query.type || req.query.q ||
req.query.contentType || req.query.sortByField ||
req.query.order || req.query.page),
options = {},
query,
hideNamespace = false;
if ( !req.query.q ) {
if (!req.query.q) {
query = DEFAULT_QUERY;
hideNamespace = true;
} else {
query = req.query.q.toString();
}
if ( VALID_TYPES.indexOf( type ) === -1 ) {
if (VALID_TYPES.indexOf(type) === -1) {
type = DEFAULT_TYPE;
}
if ( type === 'all' ) {
if (type === 'all') {
make.or();
options.title = options.user = options.description = query;
options.title = options.user = options.description = query;
}
if ( type === 'all' || type === 'tags' ) {
if (type === 'all' || type === 'tags') {
var tags = query.split(',');
options.tags = [];
options.tags[0] = tags.map(function( t ) {
options.tags[0] = tags.map(function (t) {
return t.trim();
});
} else {
// check for '@', remove
if ( query[0] === '@' ) {
if (query[0] === '@') {
query = query.slice(1);
}
options[ type ] = query;
options[type] = query;
}
if ( contentType ) {
var cleanCT = querystring.unescape( contentType );
if ( VALID_CONTENT_TYPES.indexOf( contentType ) !== -1 ) {
if (contentType) {
var cleanCT = querystring.unescape(contentType);
if (VALID_CONTENT_TYPES.indexOf(contentType) !== -1) {
options.contentType = cleanCT;
}
}
var limit = 12;
make.find( options )
.limit( limit )
.sortByField( sortByField, sortByOrder )
.page( page )
.process(function( err, data, totalHits ) {
if( err ) {
return res.send(err);
}
// query can be an array of tags sometimes,
// so force a string so that it's autoescaped
var query = type === "all" ? options.title.toString() : options[type].toString(),
showOlder = ( totalHits > page * limit );
make.find(options)
.limit(limit)
.sortByField(sortByField, sortByOrder)
.page(page)
.process(function (err, data, totalHits) {
if (err) {
return res.send(err);
}
// query can be an array of tags sometimes,
// so force a string so that it's autoescaped
var query = type === "all" ? options.title.toString() : options[type].toString(),
showOlder = (totalHits > page * limit);
if ( hideNamespace ) {
query = "featured";
}
if (hideNamespace) {
query = "featured";
}
res.render( "search.html", {
hasQuery: !!req.query.q,
makes: data || [],
page: "search",
pagination: page,
totalHits: totalHits,
limit: limit,
query: query,
searchType: type,
searchIcon: setToAll ? "all" : type
res.render("search.html", {
hasQuery: !! req.query.q,
makes: data || [],
page: "search",
pagination: page,
totalHits: totalHits,
limit: limit,
query: query,
searchType: type,
searchIcon: setToAll ? "all" : type
});
});
});
};

Просмотреть файл

@ -1,13 +1,13 @@
module.exports.login = function( req, res ){
module.exports.login = function (req, res) {
res.render('user/login.html', {
page: "login"
page: "login"
});
};
module.exports.newaccount = function( req, res ){
if ( !req.session.email ) {
return res.redirect( "/login" );
module.exports.newaccount = function (req, res) {
if (!req.session.email) {
return res.redirect("/login");
}
res.render('user/new.html', {
page: "new"
page: "new"
});
};