<commit_before>Parse.Cloud.define("sendMessage", function (request, response) {
    var params = request.params;
    if (!params.toEmail && !params.toFacebook) {
        response.error("Message needs either toEmail or toFacebook");
        return;
    }
    if (!params.image) {
        response.error("Message needs an image");
        return;
    }
    var userFinder = require('cloud/userFinder.js');
    if (params.toEmail) {
        userFinder.findByEmail(params.toEmail, function (user) {
            sendMessageToUser(user, params, "toEmail", params.toEmail, response);
        });
    } else {
        userFinder.findByFacebookID(params.toFacebook, function (user) {
            sendMessageToUser(user, params, "toFacebook", params.toFacebook, response);
        });
    }
});

function sendMessageToUser(user, params, fieldName, toUserFBIdOrEmail, response) {
    var CatImage = Parse.Object.extend("CatImage");
    var image = new CatImage();
    image.id = params.image;

    var User = Parse.Object.extend("User");
    var from = new User();
    from.id = params.fromUser;

    Parse.Cloud.useMasterKey();

    if (user) {
        var userQuery = new Parse.Query(Parse.User);
        userQuery.equalTo("objectId", user.id);

        var pushQuery = new Parse.Query(Parse.Installation);
        pushQuery.matchesQuery('user', userQuery);

        var Message = Parse.Object.extend("Message");

        var message = new Message();
        message.set("toUser", user);
        message.set("fromUser", from);
        message.set("image", image);
        message.set("messageData", params.messageData);
        message.save(null, {
            success: function (savedMessage) {
                console.log("Successfully added a message for " + user.id + " from " + params.fromUser);

                Parse.Push.send({
                        where: pushQuery,
                        data: {
                            alert: "New message on CatChat!"
                      }
                    },
                    { success: function() {
                        response.success("Successfully sent push notification");
                      }, error: function(err) {
                        response.success('Message queued, but failed to send push notification');
                      }
                    });
            },
            error: function (error) {
                response.error(error);
            }
        });
    } else {
        var PendingMessage = Parse.Object.extend("PendingMessage");

        var pm = new PendingMessage();
        pm.set(fieldName, toUserFBIdOrEmail);
        pm.set("fromUser", from);
        pm.set("image", image);
        pm.set("messageData", params.messageData);
        pm.save(null, {
            success: function (savedMessage) {
                if(fieldName == "toEmail") {
                    var constants = require('cloud/constants.js');

                    var Mailgun = require('mailgun');
                    Mailgun.initialize(constants.mailgunDomain, constants.mailgunAPIKey);

                    Mailgun.sendEmail({
                          to: toUserFBIdOrEmail,
                          from: "catchat@catchatapp.com",
                          subject: "Someone wants to chat to you on CatChat!",
                          text: "To read the messages you've been sent, sign up with this email address. \n\nWith <3 from CatChat"
                        }, {
                          success: function(httpResponse) {
                            console.log(httpResponse);
                          },
                          error: function(httpResponse) {
                            console.error(httpResponse);
                          }
                        });
                }
                response.success("Successfully added a pending message for " + toUserFBIdOrEmail + " from " + params.fromUser);
            },
            error: function (error) {
                response.error(error);
            }
        });
    }
}

Parse.Cloud.define("resendVerificationEmail", function (request, response) {
    var params = request.params;
    if(params.userid) {
        var query = new Parse.Query("User");
        query.get(params.userid, {
            success: function(user) {
                if(user) {
                    Parse.Cloud.useMasterKey();
                    // it seems the best way to resend email verification is to set the email field again
                    // https://parse.com/questions/it-would-be-nice-to-allow-users-to-request-another-email-to-verify-their-email-address
                    // https://parse.com/questions/resending-an-activation-email-to-a-user-thats-not-authenticated

                    // TODO: find a better way because this is freaking ridiculous
                    // to reset the email, we have to set it to something else, then set it back :<
                    // https://www.parse.com/questions/re-verification-of-email-address-re-sending-email-from-parse
                    user.set("email", "uhoh@catchatapp.com");
                    user.save(null, {
                      success: function(savedUser) {
                            savedUser.set("email", user.get('username'));
                            savedUser.save(null, {
                                  success: function(u) {
                                        response.success('Email verification sent');
                                  },
                                  error: function(u, error) {
                                        response.error("Failed to save email on user with id " + params.userid);
                                  }
                                });
                      },
                      error: function(savedUser, error) {
                        response.error("Failed to save email on user with id " + params.userid);
                      }
                    });
                } else {
                    response.error("Failed to lookup user with id " + params.userid);
                }
            },
            error: function(error) {
                response.error("Failed to find user with id " + params.userid);
            }
        });
    } else {
        response.error('Cannot resend verification email to user when no user provided. Expected field userid');
    }
});

Parse.Cloud.beforeSave("Message", function (request, response) {
    var message = request.object;
    var messageHelper = require('cloud/messageHelpers.js');
    if (!messageHelper.isValidMessage(message)) {
        response.error("Message not valid");
        return;
    }
    if (!messageHelper.configureMessage(message)) {
        response.error("Error configuring message");
        return;
    }
    response.success();
});

Parse.Cloud.beforeSave("PendingMessage", function (request, response) {
    var message = request.object;
    var acl = new Parse.ACL(null);
    acl.setReadAccess(message.get("fromUser"), true);
    if (!message.setACL(acl, null)) {
        response.error("error setting ACL");
        return;
    }
    response.success();
});

Parse.Cloud.beforeSave(Parse.User, function (request, response) {
    var user = request.object;
    var authData, facebookID;
    authData = user.get("authData");
    if (authData) {
        facebookID = authData.facebook.id;
    }
    if (facebookID) {
        Parse.Cloud.useMasterKey();
        user.set("facebookID", facebookID, null);
    }
    response.success();
});

Parse.Cloud.afterSave(Parse.User, function (request) {
    // we need admin rights to see all pending messages to know if this updated user can see them
    Parse.Cloud.useMasterKey();

    var user = request.object;
    var email = user.get("email");

    // move messages from PendingMessage to Messages if the user has been sent messages before having signed up
    if(user.get("email")) {
        var PendingMessage = Parse.Object.extend("PendingMessage");
        var query = new Parse.Query(PendingMessage);
        query.equalTo("toEmail", email);
        query.find({
          success: function(pendingMessages) {
            var Message = Parse.Object.extend("Message");

            var messages = [];
            for (var i = 0; i < pendingMessages.length; i++) {
                var pendingMsg = pendingMessages[i];

                messages[i] = new Message();
                messages[i].set("toUser", user);
                messages[i].set("fromUser", pendingMsg.get("fromUser"));
                messages[i].set("image", pendingMsg.get("image"));
                messages[i].set("messageData", pendingMsg.get("messageData"));
            }

            console.log("Moving " + messages.length + " pending messages into messages");

            Parse.Object.saveAll(messages, {
                success: function(list) {
                    console.log("Successfully moved users pending mesages to message table");

                    Parse.Object.destroyAll(pendingMessages);
                },
                error: function(error) {
                    console.log("Error: " + error.code + " " + error.message);
                },
              });
          },
          error: function(error) {
                console.log("Error: " + error.code + " " + error.message);
          }
        });
    }
});<commit_msg>added a notification sound and increment of the badge number on iOS<commit_after>Parse.Cloud.define("sendMessage", function (request, response) {
    var params = request.params;
    if (!params.toEmail && !params.toFacebook) {
        response.error("Message needs either toEmail or toFacebook");
        return;
    }
    if (!params.image) {
        response.error("Message needs an image");
        return;
    }
    var userFinder = require('cloud/userFinder.js');
    if (params.toEmail) {
        userFinder.findByEmail(params.toEmail, function (user) {
            sendMessageToUser(user, params, "toEmail", params.toEmail, response);
        });
    } else {
        userFinder.findByFacebookID(params.toFacebook, function (user) {
            sendMessageToUser(user, params, "toFacebook", params.toFacebook, response);
        });
    }
});

function sendMessageToUser(user, params, fieldName, toUserFBIdOrEmail, response) {
    var CatImage = Parse.Object.extend("CatImage");
    var image = new CatImage();
    image.id = params.image;

    var User = Parse.Object.extend("User");
    var from = new User();
    from.id = params.fromUser;

    Parse.Cloud.useMasterKey();

    if (user) {
        var userQuery = new Parse.Query(Parse.User);
        userQuery.equalTo("objectId", user.id);

        var pushQuery = new Parse.Query(Parse.Installation);
        pushQuery.matchesQuery('user', userQuery);

        var Message = Parse.Object.extend("Message");

        var message = new Message();
        message.set("toUser", user);
        message.set("fromUser", from);
        message.set("image", image);
        message.set("messageData", params.messageData);
        message.save(null, {
            success: function (savedMessage) {
                console.log("Successfully added a message for " + user.id + " from " + params.fromUser);

                Parse.Push.send({
                        where: pushQuery,
                        data: {
                            alert: "New message on CatChat!",
                            sound: "default",
                            badge: "Increment"
                      }
                    },
                    { success: function() {
                        response.success("Successfully sent push notification");
                      }, error: function(err) {
                        response.success('Message queued, but failed to send push notification');
                      }
                    });
            },
            error: function (error) {
                response.error(error);
            }
        });
    } else {
        var PendingMessage = Parse.Object.extend("PendingMessage");

        var pm = new PendingMessage();
        pm.set(fieldName, toUserFBIdOrEmail);
        pm.set("fromUser", from);
        pm.set("image", image);
        pm.set("messageData", params.messageData);
        pm.save(null, {
            success: function (savedMessage) {
                if(fieldName == "toEmail") {
                    var constants = require('cloud/constants.js');

                    var Mailgun = require('mailgun');
                    Mailgun.initialize(constants.mailgunDomain, constants.mailgunAPIKey);

                    Mailgun.sendEmail({
                          to: toUserFBIdOrEmail,
                          from: "catchat@catchatapp.com",
                          subject: "Someone wants to chat to you on CatChat!",
                          text: "To read the messages you've been sent, sign up with this email address. \n\nWith <3 from CatChat"
                        }, {
                          success: function(httpResponse) {
                            console.log(httpResponse);
                          },
                          error: function(httpResponse) {
                            console.error(httpResponse);
                          }
                        });
                }
                response.success("Successfully added a pending message for " + toUserFBIdOrEmail + " from " + params.fromUser);
            },
            error: function (error) {
                response.error(error);
            }
        });
    }
}

Parse.Cloud.define("resendVerificationEmail", function (request, response) {
    var params = request.params;
    if(params.userid) {
        var query = new Parse.Query("User");
        query.get(params.userid, {
            success: function(user) {
                if(user) {
                    Parse.Cloud.useMasterKey();
                    // it seems the best way to resend email verification is to set the email field again
                    // https://parse.com/questions/it-would-be-nice-to-allow-users-to-request-another-email-to-verify-their-email-address
                    // https://parse.com/questions/resending-an-activation-email-to-a-user-thats-not-authenticated

                    // TODO: find a better way because this is freaking ridiculous
                    // to reset the email, we have to set it to something else, then set it back :<
                    // https://www.parse.com/questions/re-verification-of-email-address-re-sending-email-from-parse
                    user.set("email", "uhoh@catchatapp.com");
                    user.save(null, {
                      success: function(savedUser) {
                            savedUser.set("email", user.get('username'));
                            savedUser.save(null, {
                                  success: function(u) {
                                        response.success('Email verification sent');
                                  },
                                  error: function(u, error) {
                                        response.error("Failed to save email on user with id " + params.userid);
                                  }
                                });
                      },
                      error: function(savedUser, error) {
                        response.error("Failed to save email on user with id " + params.userid);
                      }
                    });
                } else {
                    response.error("Failed to lookup user with id " + params.userid);
                }
            },
            error: function(error) {
                response.error("Failed to find user with id " + params.userid);
            }
        });
    } else {
        response.error('Cannot resend verification email to user when no user provided. Expected field userid');
    }
});

Parse.Cloud.beforeSave("Message", function (request, response) {
    var message = request.object;
    var messageHelper = require('cloud/messageHelpers.js');
    if (!messageHelper.isValidMessage(message)) {
        response.error("Message not valid");
        return;
    }
    if (!messageHelper.configureMessage(message)) {
        response.error("Error configuring message");
        return;
    }
    response.success();
});

Parse.Cloud.beforeSave("PendingMessage", function (request, response) {
    var message = request.object;
    var acl = new Parse.ACL(null);
    acl.setReadAccess(message.get("fromUser"), true);
    if (!message.setACL(acl, null)) {
        response.error("error setting ACL");
        return;
    }
    response.success();
});

Parse.Cloud.beforeSave(Parse.User, function (request, response) {
    var user = request.object;
    var authData, facebookID;
    authData = user.get("authData");
    if (authData) {
        facebookID = authData.facebook.id;
    }
    if (facebookID) {
        Parse.Cloud.useMasterKey();
        user.set("facebookID", facebookID, null);
    }
    response.success();
});

Parse.Cloud.afterSave(Parse.User, function (request) {
    // we need admin rights to see all pending messages to know if this updated user can see them
    Parse.Cloud.useMasterKey();

    var user = request.object;
    var email = user.get("email");

    // move messages from PendingMessage to Messages if the user has been sent messages before having signed up
    if(user.get("email")) {
        var PendingMessage = Parse.Object.extend("PendingMessage");
        var query = new Parse.Query(PendingMessage);
        query.equalTo("toEmail", email);
        query.find({
          success: function(pendingMessages) {
            var Message = Parse.Object.extend("Message");

            var messages = [];
            for (var i = 0; i < pendingMessages.length; i++) {
                var pendingMsg = pendingMessages[i];

                messages[i] = new Message();
                messages[i].set("toUser", user);
                messages[i].set("fromUser", pendingMsg.get("fromUser"));
                messages[i].set("image", pendingMsg.get("image"));
                messages[i].set("messageData", pendingMsg.get("messageData"));
            }

            console.log("Moving " + messages.length + " pending messages into messages");

            Parse.Object.saveAll(messages, {
                success: function(list) {
                    console.log("Successfully moved users pending mesages to message table");

                    Parse.Object.destroyAll(pendingMessages);
                },
                error: function(error) {
                    console.log("Error: " + error.code + " " + error.message);
                },
              });
          },
          error: function(error) {
                console.log("Error: " + error.code + " " + error.message);
          }
        });
    }
});
<|endoftext|>


<commit_before>
var AWS = require('aws-sdk'),
    fs  = require('fs'),
    _   = require('underscore')

var timestamp = 0, lag = 60
var config = _.defaults(eval('c='+fs.readFileSync(process.argv[2])), {
  metrics:  [],
  backends: [],
  interval: 60,
})

AWS.config.update(config)
AWS.config.apiVersions = {
  cloudwatch: '2010-08-01',
}
var cloudwatch = new AWS.CloudWatch()
var backends = _.map(config.backends, function(spec, i) {
  backend = require(spec)
  if (!backend.init(config)) {
    console.log('[cloudwatchd] failed to load backend', spec)
    process.exit(1)
  }
  return backend
})

function run() {
  var now = new Date(new Date().getTime() - lag * 1000)
  var start = timestamp
    ? new Date(timestamp)
    : new Date(now.getTime() - (config.interval * 1000))
  timestamp = now.getTime()

  _.each(config.metrics, function(m) {
    run_metric(m, start, now)
  })
}

function run_metric(metric, start, end) {
  var params = {
    Namespace: metric.Namespace,
    MetricName: metric.MetricName,
    StartTime: start.toISOString(),
      EndTime: end.toISOString(),
    Statistics: [metric.Statistic],
    Dimensions: metric.Dimensions || [],
    Period: '60',
    Unit: metric.Unit
  }

  if (config.dumpMessages)
    console.log(params)

  cloudwatch.getMetricStatistics(params, function(error, response) {
    if (error) {
      return console.error("[cloudwatchd] error:", error)
    }

    if (config.dumpMessages)
      console.log(response)

    _.each(response.Datapoints, function(dp) {
      if (config.debug) {
        console.log('[cloudwatchd]', dp.Timestamp,
          metric.Namespace, metric.MetricName, dp[metric.Statistic])
      }

      send_datapoint_to_backends(metric, dp)
    })
  })
}

function send_datapoint_to_backends(metric, dp) {
  var time = new Date(dp.Timestamp)
  var value = dp[metric.Statistic]

  _.each(backends, function(b) {
    b.send(time, metric, value)
  })
}

process.title = 'cloudwatchd'
process.on('exit', function() {
  if (config.debug)
    console.log('exiting')
})

run() || setInterval(run, config.interval * 1000)
<commit_msg>Complain if no region is specified<commit_after>
var AWS = require('aws-sdk'),
    fs  = require('fs'),
    _   = require('underscore')

var timestamp = 0, lag = 60
var config = _.defaults(eval('c='+fs.readFileSync(process.argv[2])), {
  metrics:  [],
  backends: [],
  interval: 60,
})

if (!config.region) {
  console.error('[cloudwatchd] config is missing "region"')
  process.exit(1)
}

AWS.config.update(config)
AWS.config.apiVersions = {
  cloudwatch: '2010-08-01',
}
var cloudwatch = new AWS.CloudWatch()
var backends = _.map(config.backends, function(spec, i) {
  backend = require(spec)
  if (!backend.init(config)) {
    console.log('[cloudwatchd] failed to load backend', spec)
    process.exit(1)
  }
  return backend
})

function run() {
  var now = new Date(new Date().getTime() - lag * 1000)
  var start = timestamp
    ? new Date(timestamp)
    : new Date(now.getTime() - (config.interval * 1000))
  timestamp = now.getTime()

  _.each(config.metrics, function(m) {
    run_metric(m, start, now)
  })
}

function run_metric(metric, start, end) {
  var params = {
    Namespace: metric.Namespace,
    MetricName: metric.MetricName,
    StartTime: start.toISOString(),
      EndTime: end.toISOString(),
    Statistics: [metric.Statistic],
    Dimensions: metric.Dimensions || [],
    Period: '60',
    Unit: metric.Unit
  }

  if (config.dumpMessages)
    console.log(params)

  cloudwatch.getMetricStatistics(params, function(error, response) {
    if (error) {
      return console.error("[cloudwatchd] error:", error)
    }

    if (config.dumpMessages)
      console.log(response)

    _.each(response.Datapoints, function(dp) {
      if (config.debug) {
        console.log('[cloudwatchd]', dp.Timestamp,
          metric.Namespace, metric.MetricName, dp[metric.Statistic])
      }

      send_datapoint_to_backends(metric, dp)
    })
  })
}

function send_datapoint_to_backends(metric, dp) {
  var time = new Date(dp.Timestamp)
  var value = dp[metric.Statistic]

  _.each(backends, function(b) {
    b.send(time, metric, value)
  })
}

process.title = 'cloudwatchd'
process.on('exit', function() {
  if (config.debug)
    console.log('exiting')
})

run() || setInterval(run, config.interval * 1000)
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';

treeherder.value("thPlatformNameMap", {
    "linux32": "Linux",
    "linux64": "Linux x64",
    "osx-10-6": "OS X 10.6",
    "osx-10-8": "OS X 10.8",
    "osx-10-10": "OS X 10.10",
    "windowsxp": "Windows XP",
    "windows7-32": "Windows 7",
    "windows8-32": "Windows 8",
    "windows8-64": "Windows 8 x64",
    "windows2012-64": "Windows 2012 x64",
    "android-2-2-armv6": "Android 2.2 Armv6",
    "android-2-2": "Android 2.2",
    "android-2-3-armv6": "Android 2.3 Armv6",
    "android-2-3": "Android 2.3",
    "android-2-3-armv7-api9": "Android 2.3 API9",
    "android-4-0": "Android 4.0",
    "android-4-0-armv7-api10": "Android 4.0 API10+",
    "android-4-0-armv7-api11": "Android 4.0 API11+",
    "android-4-2-x86": "Android 4.2 x86",
    "android-4-2": "Android 4.2",
    "android-4-2-armv7-api11": "Android 4.2 API11+",
    "android-4-3": "Android 4.3",
    "android-4-3-armv7-api11": "Android 4.3 API11+",
    "android-4-4": "Android 4.4",
    "android-4-4-armv7-api11": "Android 4.4 API11+",
    "android-5-0-armv7-api11": "Android 5.0 API11+",
    "b2g-linux32": "B2G Desktop Linux",
    "b2g-linux64": "B2G Desktop Linux x64",
    "b2g-osx": "B2G Desktop OS X",
    "b2g-win32": "B2G Desktop Windows",
    "b2g-emu-ics": "B2G ICS Emulator",
    "b2g-emu-jb": "B2G JB Emulator",
    "b2g-emu-kk": "B2G KK Emulator",
    "b2g-emu-l": "B2G L Emulator",
    "b2g-device-image" : "B2G Device Image",
    "mulet-linux32" : "Mulet Linux",
    "mulet-linux64" : "Mulet Linux x64",
    "mulet-osx": "Mulet OS X",
    "mulet-win32": "Mulet Windows",
    "graphene-linux64": "Graphene Linux x64",
    "graphene-osx": "Graphene OS X",
    "graphene-win64": "Graphene Windows x64",
    "other": "Other"
});

treeherder.value("thPlatformOrder", {
    "linux32": 0,
    "linux64": 1,
    "osx-10-6": 2,
    "osx-10-8": 3,
    "osx-10-10": 4,
    "windowsxp": 5,
    "windows7-32": 6,
    "windows8-32": 7,
    "windows8-64": 8,
    "windows2012-64": 9,
    "android-2-2-armv6": 10,
    "android-2-2": 11,
    "android-2-3-armv6": 12,
    "android-2-3": 13,
    "android-2-3-armv7-api9": 14,
    "android-4-0": 15,
    "android-4-0-armv7-api10": 16,
    "android-4-0-armv7-api11": 17,
    "android-4-2-x86": 18,
    "android-4-2": 19,
    "android-4-2-armv7-api11": 20,
    "android-4-3": 21,
    "android-4-3-armv7-api11": 22,
    "android-4-4": 23,
    "android-4-4-armv7-api11": 24,
    "android-5-0-armv7-api11": 25,
    "b2g-linux32": 26,
    "b2g-linux64": 27,
    "b2g-osx": 28,
    "b2g-win32": 29,
    "b2g-emu-ics": 30,
    "b2g-emu-jb": 31,
    "b2g-emu-kk": 32,
    "b2g-emu-l": 33,
    "b2g-device-image" : 34,
    "mulet-linux32" : 35,
    "mulet-linux64" : 36,
    "mulet-osx": 37,
    "mulet-win32": 38,
    "graphene-linux64": 39,
    "graphene-osx": 40,
    "graphene-win64": 41,
    "other": 99,
});

treeherder.value("thOptionOrder", {
    "opt": 0,
    "pgo": 1,
    "asan": 2,
    "debug": 3,
    "cc": 4,
});

treeherder.value("thFailureResults", ["testfailed", "busted", "exception"]);

treeherder.value("thFavicons", {
    "closed": "img/tree_closed.png",
    "open": "img/tree_open.png",
    "approval required": "img/tree_open.png",
    "unavailable": "img/tree_open.png"
});

treeherder.value("thRepoGroupOrder", {
    "development": 1,
    "project repositories": 2,
    "try": 3,
    "release-stabilization": 4,
    "taskcluster": 5,
    "qa automation tests": 6
});

treeherder.value("thDefaultRepo", "mozilla-inbound");

treeherder.value("thDateFormat", "EEE MMM d, H:mm:ss");

treeherder.value("phTimeRanges", [
      { "value":86400, "text": "Last day" },
      { "value":604800, "text": "Last 7 days" },
      { "value":1209600, "text": "Last 14 days" },
      { "value":2592000, "text": "Last 30 days" },
      { "value":5184000, "text": "Last 60 days" },
      { "value":7776000, "text": "Last 90 days" } ]);
<commit_msg>Bug 1154009 - Add back support for OS X 10.7<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';

treeherder.value("thPlatformNameMap", {
    "linux32": "Linux",
    "linux64": "Linux x64",
    "osx-10-6": "OS X 10.6",
    "osx-10-7": "OS X 10.7",
    "osx-10-8": "OS X 10.8",
    "osx-10-10": "OS X 10.10",
    "windowsxp": "Windows XP",
    "windows7-32": "Windows 7",
    "windows8-32": "Windows 8",
    "windows8-64": "Windows 8 x64",
    "windows2012-64": "Windows 2012 x64",
    "android-2-2-armv6": "Android 2.2 Armv6",
    "android-2-2": "Android 2.2",
    "android-2-3-armv6": "Android 2.3 Armv6",
    "android-2-3": "Android 2.3",
    "android-2-3-armv7-api9": "Android 2.3 API9",
    "android-4-0": "Android 4.0",
    "android-4-0-armv7-api10": "Android 4.0 API10+",
    "android-4-0-armv7-api11": "Android 4.0 API11+",
    "android-4-2-x86": "Android 4.2 x86",
    "android-4-2": "Android 4.2",
    "android-4-2-armv7-api11": "Android 4.2 API11+",
    "android-4-3": "Android 4.3",
    "android-4-3-armv7-api11": "Android 4.3 API11+",
    "android-4-4": "Android 4.4",
    "android-4-4-armv7-api11": "Android 4.4 API11+",
    "android-5-0-armv7-api11": "Android 5.0 API11+",
    "b2g-linux32": "B2G Desktop Linux",
    "b2g-linux64": "B2G Desktop Linux x64",
    "b2g-osx": "B2G Desktop OS X",
    "b2g-win32": "B2G Desktop Windows",
    "b2g-emu-ics": "B2G ICS Emulator",
    "b2g-emu-jb": "B2G JB Emulator",
    "b2g-emu-kk": "B2G KK Emulator",
    "b2g-emu-l": "B2G L Emulator",
    "b2g-device-image" : "B2G Device Image",
    "mulet-linux32" : "Mulet Linux",
    "mulet-linux64" : "Mulet Linux x64",
    "mulet-osx": "Mulet OS X",
    "mulet-win32": "Mulet Windows",
    "graphene-linux64": "Graphene Linux x64",
    "graphene-osx": "Graphene OS X",
    "graphene-win64": "Graphene Windows x64",
    "other": "Other"
});

treeherder.value("thPlatformOrder", {
    "linux32": 0,
    "linux64": 1,
    "osx-10-6": 10,
    "osx-10-7": 11,
    "osx-10-8": 12,
    "osx-10-10": 13,
    "windowsxp": 20,
    "windows7-32": 21,
    "windows8-32": 22,
    "windows8-64": 23,
    "windows2012-64": 24,
    "android-2-2-armv6": 30,
    "android-2-2": 31,
    "android-2-3-armv6": 32,
    "android-2-3": 33,
    "android-2-3-armv7-api9": 34,
    "android-4-0": 35,
    "android-4-0-armv7-api10": 36,
    "android-4-0-armv7-api11": 37,
    "android-4-2-x86": 38,
    "android-4-2": 39,
    "android-4-2-armv7-api11": 40,
    "android-4-3": 41,
    "android-4-3-armv7-api11": 42,
    "android-4-4": 43,
    "android-4-4-armv7-api11": 44,
    "android-5-0-armv7-api11": 45,
    "b2g-linux32": 50,
    "b2g-linux64": 51,
    "b2g-osx": 52,
    "b2g-win32": 53,
    "b2g-emu-ics": 54,
    "b2g-emu-jb": 55,
    "b2g-emu-kk": 56,
    "b2g-emu-l": 57,
    "b2g-device-image" : 58,
    "mulet-linux32" : 60,
    "mulet-linux64" : 61,
    "mulet-osx": 62,
    "mulet-win32": 63,
    "graphene-linux64": 71,
    "graphene-osx": 72,
    "graphene-win64": 73,
    "other": 99,
});

treeherder.value("thOptionOrder", {
    "opt": 0,
    "pgo": 1,
    "asan": 2,
    "debug": 3,
    "cc": 4,
});

treeherder.value("thFailureResults", ["testfailed", "busted", "exception"]);

treeherder.value("thFavicons", {
    "closed": "img/tree_closed.png",
    "open": "img/tree_open.png",
    "approval required": "img/tree_open.png",
    "unavailable": "img/tree_open.png"
});

treeherder.value("thRepoGroupOrder", {
    "development": 1,
    "project repositories": 2,
    "try": 3,
    "release-stabilization": 4,
    "taskcluster": 5,
    "qa automation tests": 6
});

treeherder.value("thDefaultRepo", "mozilla-inbound");

treeherder.value("thDateFormat", "EEE MMM d, H:mm:ss");

treeherder.value("phTimeRanges", [
      { "value":86400, "text": "Last day" },
      { "value":604800, "text": "Last 7 days" },
      { "value":1209600, "text": "Last 14 days" },
      { "value":2592000, "text": "Last 30 days" },
      { "value":5184000, "text": "Last 60 days" },
      { "value":7776000, "text": "Last 90 days" } ]);
<|endoftext|>


<commit_before>var FbAPI = require('../common/fb-api').FbAPI
var redisUtil = require('../common/redis-util')
var client = redisUtil.initClient()
var REACTION_TYPES = require('../common/meta').REACTION_TYPES
var _ = require('lodash')

var moment = require('moment')

function asRatio (reactions, total) {
  return _.pick(_.mapValues(reactions, function (v, k, o) {
    return v / total
  }), REACTION_TYPES)
}

function _locationKey (location) {
  return location + '_result'
}
function _dateRangeKey (start, end) {
  return [start, end].join('_')
}
// fetch page again for content before write
// practically store daily now but support range for future
function cacheWrite (location, start, end, resultByDateRange) {
  var key = _locationKey(location)
  var dateRangeKey = _dateRangeKey(start, end)

  console.log('Write to cache' + key)
  return client.hmsetAsync(key, dateRangeKey, JSON.stringify(resultByDateRange))
}

// TODO true limit by range, now take 7 days

function cacheRead (location, start, end) {
  var key = _locationKey(location)
  var days = Math.ceil((end - start) / 86400000)
  // TODO refactor as duplicated
  var offset = moment().diff(moment(end), 'days')
  console.log('read for ' + days + 'offset:' + offset)
  var dateRangekeys = _.range(0, days).map(function (d) {
    var start = moment().startOf('day').subtract(offset + d, 'days').format('x')
    var end = moment().endOf('day').subtract(offset + d, 'days').format('x')
    return _dateRangeKey(start, end)
  })
  console.log(dateRangekeys)
  return client.hmgetAsync(key, dateRangekeys)
    .then(function (data) {
      return _.zipObject(dateRangekeys, _.map(data, JSON.parse))
    })
}

// TODO together 1 structure or separate? separate for now as past data
function metaKey (id) {
  return id + '_meta'
}

function loadPostsMetadata (postIds) {
  return redisUtil.multiHgetallAsync(client, postIds.map(metaKey))
    .then(function (data) {
      return _.keyBy(_.compact(data), 'id')
    })
}
function resultByDateRange (location, start, end, aggReactions) {
  // TODO _.invokeMap([{'a':1},{'b':1}],_.get,'b')
  var ids = _.map(aggReactions['tops'], 'id')
  return loadPostsMetadata(ids)
    .then(function (meta) {
      aggReactions['tops'] = _.map(aggReactions['tops'], function (top, i) {
        var extra = meta[top.id] ? meta[top.id] : {}
        return _.assign(top, extra)
      })
      aggReactions['ratio'] = asRatio(aggReactions['reactions'], aggReactions['summary']['total'])
      return aggReactions
    })
}

module.exports = {
  resultByDateRange: resultByDateRange,
  loadPostsMetadata: loadPostsMetadata,
  cacheWrite: cacheWrite,
  cacheRead: cacheRead,
  asRatio: asRatio
}
<commit_msg>fix off-by-1<commit_after>var FbAPI = require('../common/fb-api').FbAPI
var redisUtil = require('../common/redis-util')
var client = redisUtil.initClient()
var REACTION_TYPES = require('../common/meta').REACTION_TYPES
var _ = require('lodash')

var moment = require('moment')

function asRatio (reactions, total) {
  return _.pick(_.mapValues(reactions, function (v, k, o) {
    return v / total
  }), REACTION_TYPES)
}

function _locationKey (location) {
  return location + '_result'
}
function _dateRangeKey (start, end) {
  return [start, end].join('_')
}
// fetch page again for content before write
// practically store daily now but support range for future
function cacheWrite (location, start, end, resultByDateRange) {
  var key = _locationKey(location)
  var dateRangeKey = _dateRangeKey(start, end)

  console.log('Write to cache' + key)
  return client.hmsetAsync(key, dateRangeKey, JSON.stringify(resultByDateRange))
}

// TODO true limit by range, now take 7 days

function cacheRead (location, start, end) {
  var key = _locationKey(location)
  var days = Math.ceil((end - start) / 86400000)
  // TODO refactor as duplicated
  var offset = moment().diff(moment(end).startOf('day'), 'days')
  console.log('read for ' + days + 'offset:' + offset)
  var dateRangekeys = _.range(0, days).map(function (d) {
    var start = moment().startOf('day').subtract(offset + d, 'days').format('x')
    var end = moment().endOf('day').subtract(offset + d, 'days').format('x')
    return _dateRangeKey(start, end)
  })
  console.log(dateRangekeys)
  return client.hmgetAsync(key, dateRangekeys)
    .then(function (data) {
      return _.zipObject(dateRangekeys, _.map(data, JSON.parse))
    })
}

// TODO together 1 structure or separate? separate for now as past data
function metaKey (id) {
  return id + '_meta'
}

function loadPostsMetadata (postIds) {
  return redisUtil.multiHgetallAsync(client, postIds.map(metaKey))
    .then(function (data) {
      return _.keyBy(_.compact(data), 'id')
    })
}
function resultByDateRange (location, start, end, aggReactions) {
  // TODO _.invokeMap([{'a':1},{'b':1}],_.get,'b')
  var ids = _.map(aggReactions['tops'], 'id')
  return loadPostsMetadata(ids)
    .then(function (meta) {
      aggReactions['tops'] = _.map(aggReactions['tops'], function (top, i) {
        var extra = meta[top.id] ? meta[top.id] : {}
        return _.assign(top, extra)
      })
      aggReactions['ratio'] = asRatio(aggReactions['reactions'], aggReactions['summary']['total'])
      return aggReactions
    })
}

module.exports = {
  resultByDateRange: resultByDateRange,
  loadPostsMetadata: loadPostsMetadata,
  cacheWrite: cacheWrite,
  cacheRead: cacheRead,
  asRatio: asRatio
}
<|endoftext|>


<commit_before>import React, {useRef, useState, useEffect} from 'react'
import PropTypes from 'prop-types'
import {useIsMounted} from 'hooks/useIsMounted'
import Clipboard from 'clipboard'

const COPIED_TIMEOUT = 1500

const CopyButton = ({text, className, label = 'Copy', successLabel = 'Copied', errorLabel = 'Error'}) => {
  const copyButton = useRef()
  const clipboard = useRef()
  const mounted = useIsMounted()
  const [copiedSuccess, setCopiedSuccess] = useState(false)
  const [copiedError, setCopiedError] = useState(false)

  useEffect(() => {
    const resetState = () => {
      setTimeout(() => {
        if (clipboard.current && mounted.current) {
          setCopiedSuccess(false)
          setCopiedError(false)
        }
      }, COPIED_TIMEOUT)
    }

    if (mounted.current && copyButton.current) {
      clipboard.current = new Clipboard(copyButton.current)
      clipboard.current.on('success', () => {
        setCopiedSuccess(true)
        resetState()
      })
      clipboard.current.on('error', () => {
        setCopiedError(true)
        resetState()
      })

      return () => {
        if (clipboard.current) {
          clipboard.current.destroy()
          clipboard.current = null
        }
      }
    }

    return () => {}
  }, [mounted])

  const renderLabel = () => {
    if (copiedSuccess) {
      return successLabel
    } else if (copiedError) {
      return errorLabel
    } else {
      return label
    }
  }

  return (
    <button
      className={className}
      ref={copyButton}
      data-clipboard-text={text}>
      {renderLabel()}
    </button>
  )
}

CopyButton.propTypes = {
  className: PropTypes.string,
  text: PropTypes.string.isRequired,
  label: PropTypes.string,
  successLabel: PropTypes.string,
  errorLabel: PropTypes.string
}

export default CopyButton
<commit_msg>new theme switcher<commit_after>import React, {useRef, useState, useEffect} from 'react'
import PropTypes from 'prop-types'
import {useIsMounted} from 'hooks/useIsMounted'
import Clipboard from 'clipboard'

const COPIED_TIMEOUT = 2000

const CopyButton = ({text, className, label = 'Copy', successLabel = 'Copied', errorLabel = 'Error'}) => {
  const copyButton = useRef()
  const clipboard = useRef()
  const mounted = useIsMounted()
  const [copiedSuccess, setCopiedSuccess] = useState(false)
  const [copiedError, setCopiedError] = useState(false)

  useEffect(() => {
    const resetState = () => {
      setTimeout(() => {
        if (clipboard.current && mounted.current) {
          setCopiedSuccess(false)
          setCopiedError(false)
        }
      }, COPIED_TIMEOUT)
    }

    if (mounted.current && copyButton.current) {
      clipboard.current = new Clipboard(copyButton.current)
      clipboard.current.on('success', () => {
        setCopiedSuccess(true)
        resetState()
      })
      clipboard.current.on('error', () => {
        setCopiedError(true)
        resetState()
      })

      return () => {
        if (clipboard.current) {
          clipboard.current.destroy()
          clipboard.current = null
        }
      }
    }

    return () => {}
  }, [mounted])

  const renderLabel = () => {
    if (copiedSuccess) {
      return successLabel
    } else if (copiedError) {
      return errorLabel
    } else {
      return label
    }
  }

  return (
    <button
      className={className}
      ref={copyButton}
      data-clipboard-text={text}>
      {renderLabel()}
    </button>
  )
}

CopyButton.propTypes = {
  className: PropTypes.string,
  text: PropTypes.string.isRequired,
  label: PropTypes.string,
  successLabel: PropTypes.string,
  errorLabel: PropTypes.string
}

export default CopyButton
<|endoftext|>


<commit_before>/**
 * Definition for a binary tree node:
 */
export class TreeNode {
    constructor(val) {
        this.val = val;
        this.left = this.right = null;
    }
}

/****
 * Generate binary tree base on node values array.
 * Basic idea:
    1. Use parentNodes[node] to keep record;
    2. Search for needed num of child in valArray for each node in parentNodes;
    3. Loop until beyond length of valArray.

 * Used in: [102, 104, 111, 226]
 ***/
export const getBinaryTreeFromArray = (valArray) => {
    if (!(Array.isArray(valArray) && valArray.length > 0 && valArray[0])) {
        return null;
    }

    let rootNode = new TreeNode(valArray[0]),
        arrAnchorIndex = 1,
        parentNodes = [rootNode];

    while (parentNodes.length > 0 && arrAnchorIndex < valArray.length) {
        let parentNodesIndex = 0,
            curDepthLength = parentNodes.length;

        // assign children for parentNodes
        while (parentNodesIndex < curDepthLength) {
            let curParentNode = parentNodes.shift(),
                childNodesIndex = 0;

            while (childNodesIndex < 2) {
                let val = valArray[arrAnchorIndex],
                    curNode = null;

                if (val) {
                    curNode = new TreeNode(val);
                    parentNodes.push(curNode); // push non-null nodes to parentNode for next loop
                }

                if (childNodesIndex === 0) {
                    curParentNode.left = curNode;
                } else {
                    curParentNode.right = curNode;
                }

                childNodesIndex++;
                arrAnchorIndex++;

                // avoid in vain looping out of valArray's bound
                if (arrAnchorIndex >= valArray.length) {
                    return rootNode;
                }
            }

            parentNodesIndex++;
        }
    }

    return rootNode;
};

/****
 * Convert binary tree to array.
 * Basic idea:
    1. loop each depth of the tree in bfs style
    2. check each child node of nodes in queue, only care each node's next generations.

 * Used in: [226]
 ***/
export const getArrayFromBinaryTree = (root) => {
    const isNode = (node) => {
        return (node instanceof TreeNode) && node.val !== null;
    };

    if (!isNode(root)) {
        return [];
    }

    let _queue = [root],
        bTreeArray = [root.val],
        nullChainCount = 0;

    while (_queue.length > 0) {
        let curDepthLength = _queue.length,
            curNode = _queue.shift();

        if (isNode(curNode.left)) {
            bTreeArray.push(curNode.left.val);
            _queue.push(curNode.left);

            nullChainCount = 0;
        } else {
            bTreeArray.push(null);
            nullChainCount++;
        }

        if (isNode(curNode.right)) {
            bTreeArray.push(curNode.right.val);
            _queue.push(curNode.right);

            nullChainCount = 0;
        } else {
            bTreeArray.push(null);
            nullChainCount++;
        }
    }

    if (nullChainCount > 0) {
        bTreeArray = bTreeArray.slice(0, -nullChainCount);
    }

    return bTreeArray;
};
<commit_msg>added big O for bTree utils<commit_after>/**
 * Definition for a binary tree node:
 */
export class TreeNode {
    constructor(val) {
        this.val = val;
        this.left = this.right = null;
    }
}

/****
 * Generate binary tree base on node values array.
 * Basic idea:
    1. Use parentNodes[node] to keep record;
    2. Search for needed num of child in valArray for each node in parentNodes;
    3. Loop until beyond length of valArray.
 *
 * "N" is node count
 * Time complexity: O(N)
 * Space complexity: O(N)
 *
 * Used in: [102, 104, 111, 226]
 ***/
export const getBinaryTreeFromArray = (valArray) => {
    if (!(Array.isArray(valArray) && valArray.length > 0 && valArray[0])) {
        return null;
    }

    let rootNode = new TreeNode(valArray[0]),
        arrAnchorIndex = 1,
        parentNodes = [rootNode];

    while (parentNodes.length > 0 && arrAnchorIndex < valArray.length) {
        let parentNodesIndex = 0,
            curDepthLength = parentNodes.length;

        // assign children for parentNodes
        while (parentNodesIndex < curDepthLength) {
            let curParentNode = parentNodes.shift(),
                childNodesIndex = 0;

            while (childNodesIndex < 2) {
                let val = valArray[arrAnchorIndex],
                    curNode = null;

                if (val) {
                    curNode = new TreeNode(val);
                    parentNodes.push(curNode); // push non-null nodes to parentNode for next loop
                }

                if (childNodesIndex === 0) {
                    curParentNode.left = curNode;
                } else {
                    curParentNode.right = curNode;
                }

                childNodesIndex++;
                arrAnchorIndex++;

                // avoid in vain looping out of valArray's bound
                if (arrAnchorIndex >= valArray.length) {
                    return rootNode;
                }
            }

            parentNodesIndex++;
        }
    }

    return rootNode;
};

/****
 * Convert binary tree to array.
 * Basic idea:
    1. loop each depth of the tree in bfs style
    2. check each child node of nodes in queue, only care each node's next generations.
 *
 * "N" is node count
 * Time complexity: O(2N)
 * Space complexity: O(2N)
 *
 * Used in: [226]
 ***/
export const getArrayFromBinaryTree = (root) => {
    const isNode = (node) => {
        return (node instanceof TreeNode) && node.val !== null;
    };

    if (!isNode(root)) {
        return [];
    }

    let _queue = [root],
        bTreeArray = [root.val],
        nullChainCount = 0;

    while (_queue.length > 0) {
        let curDepthLength = _queue.length,
            curNode = _queue.shift();

        if (isNode(curNode.left)) {
            bTreeArray.push(curNode.left.val);
            _queue.push(curNode.left);

            nullChainCount = 0;
        } else {
            bTreeArray.push(null);
            nullChainCount++;
        }

        if (isNode(curNode.right)) {
            bTreeArray.push(curNode.right.val);
            _queue.push(curNode.right);

            nullChainCount = 0;
        } else {
            bTreeArray.push(null);
            nullChainCount++;
        }
    }

    if (nullChainCount > 0) {
        bTreeArray = bTreeArray.slice(0, -nullChainCount); // any ways to optimize this? O(n) time complexity here
    }

    return bTreeArray;
};
<|endoftext|>


<commit_before>var FileRenderer = require('../filerenderer.js');
var FileRevisions = require('../fileRevisions.js');

if (window.contextVars.renderURL !== undefined) {
    FileRenderer.start(window.contextVars.renderURL, '#fileRendered');
}

new FileRevisions(
    '#fileRevisions',
    window.contextVars.node,
    window.contextVars.file,
    window.contextVars.currentUser.canEdit
);

FileRenderer.start(window.contextVars.renderURL, '#fileRendered');
<commit_msg>Remove extra call to to FileRenderer.start<commit_after>var FileRenderer = require('../filerenderer.js');
var FileRevisions = require('../fileRevisions.js');

if (window.contextVars.renderURL !== undefined) {
    FileRenderer.start(window.contextVars.renderURL, '#fileRendered');
}

new FileRevisions(
    '#fileRevisions',
    window.contextVars.node,
    window.contextVars.file,
    window.contextVars.currentUser.canEdit
);
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');
var ko = require('knockout');

var osfHelpers = require('osfHelpers');
var Paginator = require('js/paginator');
var oop = require('js/oop');

describe('paginator', () => {

    var returnTrue = function() {
        return true;
    };

    var returnFalse = function() {
        return false;
    };

    var parentIsFolder = function(){
        return {
            data: {
                node_id: 'normalFolder'
            }
        };
    };

    var parentIsNotFolder = function(){
        return {
            data: {
                node_id: 'noParent'
            }
        };
    };
    var parent = {
        name: 'Parent',
        isAncestor: returnTrue
    };

    var child = {
        name: 'Child',
        isAncestor: returnFalse
    };<commit_msg>[skip ci] work in process paginator js tests<commit_after>'use strict';

var $ = require('jquery');
var ko = require('knockout');

var osfHelpers = require('osfHelpers');
var Paginator = require('js/paginator');
var oop = require('js/oop');

describe('paginator', () => {

    var numberofPages = function(){
        return 5;
    };

    var currentPage = function(){
        return 1;
    };

    var paginators = function(){
        return [];
    };

    it('nextPage', () => {
        var newCurrentPage = Paginator.nextPage();
        assert.equal(newCurrentPage, currentPage + 1);
    });

    it('previousPage', () => {
        var newCurrentPage = Paginator.previousPage();
        assert.equal(newCurrentPage, currentPage - 1);
    });

    it('search', () => {
        var error = Paginator.previousPage();
        assert.equal(error, 'Paginator subclass must define a "search" method.');
    });

    it('addNewPaginator', () => {
        var newPaginator = Paginator.addNewPaginators();
        assert.equal(paginators.length(), 1);
    });
});<|endoftext|>


<commit_before>// Reusable sidebar module
//
// usage: $('#fixed-side-bar').fixedSideBar()
//
// Should also call $('#fixed-side-bar').resizeSideBar() when either the sidebar or main
// content changes, to avoid display issues when the sidebar is longer than the content
//
// Note: Depends on document elements with the ids "content" and "mainContent"
// 		#content should contain all content including the sidebar
// 		#mainContent should contain all other content (without the sidebar)

(function($) {
	var top = 0, initOffset = 0;
	var sideBar;

	$.fn.fixedSideBar = function() {

		// save a reference to "this" so that we can refer to it in the event handlers below
		sideBar = this;

		// save the current position of the filter bar to use when scrolling
		top = this.offset().top - parseInt(this.css('margin-top'));
		initOffset = this.css('top');

		// when the window scrolls, need to adjust the position of the filter bar
		$(window).scroll(function(event) {
			// check the vertical position of the scroll
		    var y = $(this).scrollTop();

		    // is it below the form?
		    if (y >= top) {
		        // if so, set fixed position
		        sideBar.css('position', 'fixed');
		        sideBar.css('top', '0');
		        sideBar.css('left', parseInt($('#content').css('margin-left')) + "px");
		    } else {
		        // otherwise set absolute position
		        sideBar.css('position', 'absolute');
		        sideBar.css('top', initOffset);
		        sideBar.css('left', "0");
		    }
		});

		// when the window is resized, need to adjust the filter bar position and
		// publication list height to avoid formatting issues
		$(window).resize(function(event) {
			var minHeight = sideBar.height() + 10; // TODO: should probably use something from the css rather than a magic number here
			var content = $('#main-content');
			content.css('min-height', minHeight + "px");

			if(sideBar.css('position') == "fixed") {
				sideBar.css('left', parseInt($('#content').css('margin-left')) + "px");
			} else {
				sideBar.css('left', 0);
			}
		});

		return this;
	};

	$.fn.resizeSideBar = function() {
		var minHeight = this.height() + 10; // TODO: should probably use something from the css rather than a magic number here
		var content = $('#main-content');
		content.css('min-height', minHeight + "px");

		if(this.css('position') == "fixed") {
			this.css('left', parseInt($('#content').css('margin-left')) + "px");
		} else {
			this.css('left', 0);
		}

		return this;
	};
}(jQuery));<commit_msg>Fixed Undo<commit_after>// Reusable sidebar module
//
// usage: $('#fixed-side-bar').fixedSideBar()
//
// Should also call $('#fixed-side-bar').resizeSideBar() when either the sidebar or main
// content changes, to avoid display issues when the sidebar is longer than the content
//
// Note: Depends on document elements with the ids "content" and "mainContent"
// 		#content should contain all content including the sidebar
// 		#mainContent should contain all other content (without the sidebar)

(function($) {
	var top = 0, initOffset = 0;
	var sideBar;

	$.fn.fixedSideBar = function() {

		// save a reference to "this" so that we can refer to it in the event handlers below
		sideBar = this;

		// save the current position of the filter bar to use when scrolling
		top = this.offset().top - parseInt(this.css('margin-top'));
		initOffset = this.css('top');

		// when the window scrolls, need to adjust the position of the filter bar
		$(window).scroll(function(event) {
			// check the vertical position of the scroll
		    var y = $(this).scrollTop();
		    var footer = $(".makelab-footer");

		    // is it below the form?
		    if (y >= top && y <= $('content').height() - 50) {
		        // if so, set fixed position
		        sideBar.css('position', 'fixed');
		        sideBar.css('top', '0');
		        sideBar.css('left', parseInt($('#content').css('margin-left')) + "px");
		    } else {
		        if (y <= top) {
		        	sideBar.css('position', 'absolute');
		        	sideBar.css('top', initOffset);
		        	sideBar.css('left', 0);
		        } else {
		        	sideBar.css('position', 'absolute');
		        	sideBar.css('top', $('#content').height() - footer.height() - 5);
		        	sideBar.css('left', 0);
		        }
		    }
		});

		// when the window is resized, need to adjust the filter bar position and
		// publication list height to avoid formatting issues
		$(window).resize(function(event) {
			var minHeight = sideBar.height() + 10; // TODO: should probably use something from the css rather than a magic number here
			var content = $('#main-content');
			content.css('min-height', minHeight + "px");

			if(sideBar.css('position') == "fixed") {
				sideBar.css('left', parseInt($('#content').css('margin-left')) + "px");
			} else {
				sideBar.css('left', 0);
			}
		});

		return this;
	};

	$.fn.resizeSideBar = function() {
		var minHeight = this.height() + 10; // TODO: should probably use something from the css rather than a magic number here
		var content = $('#main-content');
		content.css('min-height', minHeight + "px");

		if(this.css('position') == "fixed") {
			this.css('left', parseInt($('#content').css('margin-left')) + "px");
		} else {
			this.css('left', 0);
		}

		return this;
	};
}(jQuery));<|endoftext|>


<commit_before>angular.module('pvta.factories')

.factory('FavoriteStops', function () {
  var stops = [];
  var push = function (stop) {
    localforage.getItem('favoriteStops', function (err, stops) {
      var newStop = {StopId: stop.StopId, Name: stop.Name};
      if (stops) {
        stops.push(newStop);
        localforage.setItem('favoriteStops', stops);
      }
      else {
        var favoriteStops = [newStop];
        localforage.setItem('favoriteStops', favoriteStops);
      }
    });
  };

  var getAll = function () {
    localforage.getItem('favoriteStops', function (err) {
      if (err) {
        console.log('Error getting all favorite stops: ' + err);
      }
    });
  };

  var remove = function (stop) {
    localforage.getItem('favoriteStops', function (err, stops) {
      for (var i = 0; i < stops.length; i++) {
        if (stops[i].StopId === stop.StopId) {
          stops.splice(i, 1);
        }
      }
      localforage.setItem('favoriteStops', stops, function (err) {
        if (err) {
          console.log('Error removing favorite stop: ' + err);
        }
      });
    });
  };

  function contains (stopId, cb) {
    localforage.getItem('favoriteStops', function (err, stops) {
      if (stops) {
        var r = _.where(stops, { StopId: stopId });
        if (r.length > 0) {
          cb(true);
        }
        else {
          cb(false);
        }
      }
      else {
        cb(false);
      }
    });
  }
  return {
    push: push,
    getAll: getAll,
    remove: remove,
    contains: contains
  };
});
<commit_msg>Variable renamed<commit_after>angular.module('pvta.factories')

.factory('FavoriteStops', function () {
  var stops = [];
  var push = function (stop) {
    localforage.getItem('favoriteStops', function (err, stops) {
      var newStop = {StopId: stop.StopId, Name: stop.Name};
      if (stops) {
        stops.push(newStop);
        localforage.setItem('favoriteStops', stops);
      }
      else {
        var favoriteStops = [newStop];
        localforage.setItem('favoriteStops', favoriteStops);
      }
    });
  };

  var getAll = function () {
    localforage.getItem('favoriteStops', function (err) {
      if (err) {
        console.log('Error getting all favorite stops: ' + err);
      }
    });
  };

  var remove = function (stop) {
    localforage.getItem('favoriteStops', function (err, stops) {
      for (var i = 0; i < stops.length; i++) {
        if (stops[i].StopId === stop.StopId) {
          stops.splice(i, 1);
        }
      }
      localforage.setItem('favoriteStops', stops, function (err) {
        if (err) {
          console.log('Error removing favorite stop: ' + err);
        }
      });
    });
  };

  function contains (stopId, cb) {
    localforage.getItem('favoriteStops', function (err, stops) {
      if (stops) {
        var filteredStops = _.where(stops, { StopId: stopId });
        if (filteredStops.length > 0) {
          cb(true);
        }
        else {
          cb(false);
        }
      }
      else {
        cb(false);
      }
    });
  }
  return {
    push: push,
    getAll: getAll,
    remove: remove,
    contains: contains
  };
});
<|endoftext|>


<commit_before>import firebase from 'firebase';
import { FETCH_PROJECTS } from './types';

const database = app.database();
const projects = database.ref('projects');

// const INITIAL_PROJECTS = [{ id: 1, name: 'Tower' },
//                           { id: 2, name: 'Apartment' },
//                           { id: 3, name: 'Office' }];

// export function fetchProjects() {
//   return {
//     type: FETCH_PROJECTS,
//     payload: INITIAL_PROJECTS
//   };
// }

export function fetchProjects() {
  return dispatch => {
    projects.on('value', snapshot => {
      dispatch({
        type: FETCH_PROJECTS,
        payload: snapshot.val()
      })
    })
  }
}
<commit_msg>remove mock data<commit_after>import firebase from 'firebase';
import { FETCH_PROJECTS } from './types';

const projects = firebaseDb.ref('projects');

export function fetchProjects() {
  return dispatch => {
    projects.on('value', snapshot => {
      dispatch({
        type: FETCH_PROJECTS,
        payload: snapshot.val()
      })
    })
  }
}
<|endoftext|>


<commit_before>/**
 * Simple color entry widget
 *
 * @copyright 2005-2007 silverorange Inc.
 */

/**
 * Creates a SwatSimpleColorEntry object
 *
 * @param string id
 * @param Array colors
 */
function SwatSimpleColorEntry(id, colors)
{
	this.id = id;
	this.colors = colors;
	this.is_open = false;
	this.is_drawn = false;
	this.is_positioned = false;

	this.input_tag = document.getElementById(this.id + '_value');
	this.swatch = document.getElementById(this.id + '_swatch');

	this.hex_input_tag = document.createElement('input');
	this.hex_input_tag.type = 'text';
	this.hex_input_tag.id = this.id + '_hex_color';
	this.hex_input_tag.size = 6;

	YAHOO.util.Event.addListener(this.hex_input_tag, 'change',
		this.handleInputChange, this, true);

	YAHOO.util.Event.addListener(this.hex_input_tag, 'keyup',
		this.handleInputChange, this, true);

	// this tries to make a square palette
	this.columns = Math.ceil(Math.sqrt(this.colors.length));

	this.current_color = null;
	this.colorChangeEvent = new YAHOO.util.CustomEvent('colorChange');

	this.setColor(this.input_tag.value);

	this.drawButton();
	this.drawPalette();
	this.drawInput();

	YAHOO.util.Event.onContentReady(this.id + '_palette',
		this.createOverlay, this, true)
}

SwatSimpleColorEntry.set_text = 'Set';

/**
 * Displays the toggle button for this simple color entry
 */
SwatSimpleColorEntry.prototype.drawButton = function()
{
	this.toggle_button = document.createElement('button');
	YAHOO.util.Dom.addClass(this.toggle_button,
		'swat-simple-color-entry-toggle-button');

	// the type property is readonly in IE so use setAttribute() here
	this.toggle_button.setAttribute('type', 'button');

	this.swatch.parentNode.replaceChild(this.toggle_button, this.swatch);
	this.toggle_button.appendChild(this.swatch);
	YAHOO.util.Event.addListener(this.toggle_button, 'click', this.toggle,
		this, true);

	this.palette = document.createElement('div');
	this.palette.id = this.id + '_palette';
	YAHOO.util.Dom.addClass(this.palette, 'swat-simple-color-entry-palette');
	this.palette.style.display = 'none';

	var overlay_header = document.createElement('div');
	YAHOO.util.Dom.addClass(overlay_header, 'hd');

	var overlay_body = document.createElement('div');
	YAHOO.util.Dom.addClass(overlay_body, 'bd');

	var overlay_footer = document.createElement('div');
	YAHOO.util.Dom.addClass(overlay_footer, 'ft');

	this.palette.appendChild(overlay_header);
	this.palette.appendChild(overlay_body);
	this.palette.appendChild(overlay_footer);

	var container = document.getElementById(this.id);
	container.appendChild(this.palette);
}

/**
 * Creates simple color entry overlay widget when toggle button has been drawn
 */
SwatSimpleColorEntry.prototype.createOverlay = function(event)
{
	this.overlay = new YAHOO.widget.Overlay(this.id + '_palette',
		{ visible: false, constraintoviewport: true });

	this.overlay.render(document.body);
	this.palette.style.display = 'block';
	this.is_drawn = true;
}

/**
 * Closes this color palette
 */
SwatSimpleColorEntry.prototype.close = function()
{
	this.overlay.hide();
	SwatZIndexManager.lowerElement(this.palette);
	this.is_open = false;
}

/**
 * Opens this color palette
 */
SwatSimpleColorEntry.prototype.open = function()
{
	if (!this.is_positioned) {
		this.overlay.cfg.setProperty('context',
			[this.toggle_button, 'tl', 'bl']);

		this.is_positioned = true;
	}

	this.overlay.show();
	SwatZIndexManager.raiseElement(this.palette);
	this.is_open = true;
}

/**
 * Draws the hex input box
 */
SwatSimpleColorEntry.prototype.drawInput = function()
{
	var div_tag = document.createElement('div');
	div_tag.className = 'swat-simple-color-entry-palette-hex-color';

	var label_tag = document.createElement('label');
	label_tag.htmlFor = this.id + '_hex_color';
	var title = document.createTextNode('#');
	label_tag.appendChild(title);

	var button_tag = document.createElement('button');
	button_tag.setAttribute('type', 'button');
	var title = document.createTextNode(SwatSimpleColorEntry.set_text);
	button_tag.appendChild(title);
	YAHOO.util.Event.addListener(button_tag, 'click', this.toggle, this, true);

	div_tag.appendChild(label_tag);
	div_tag.appendChild(this.hex_input_tag);
	div_tag.appendChild(button_tag);

	this.palette.childNodes[1].appendChild(div_tag);
}

SwatSimpleColorEntry.prototype.handleInputChange = function()
{
	var color = this.hex_input_tag.value;

	if (color[0] == '#') {
		color = color.slice(1, color.length - 1);
	}

	if (color.length == 3) {
		var hex3 = /^[0-9a-f]{3}$/i;
		if (!hex3.test(color)) {
			color = null;
		}
	} else if (color.length == 6) {
		var hex6 = /^[0-9a-f]{6}$/i;
		if (!hex6.test(color)) {
			color = null;
		}
	} else {
		color = null;
	}

	this.setColor(color);
}

/**
 * Draws this color palette
 */
SwatSimpleColorEntry.prototype.drawPalette = function()
{
	var table = document.createElement('table');
	table.cellSpacing = '1';

	var tbody = document.createElement('tbody');

	if (this.colors.length % this.columns == 0)
		var num_cells = this.colors.length
	else
		var num_cells = this.colors.length +
			(this.columns - (this.colors.length % this.columns));

	var trow;
	var tcell;
	var anchor;
	var text;

	for (var i = 0; i < num_cells; i++) {
		if (i % this.columns == 0)
			trow = document.createElement('tr');

		tcell = document.createElement('td');
		text = document.createTextNode(' '); // non-breaking UTF-8 space

		if (i < this.colors.length) {
			tcell.id = this.id + '_palette_' + i;
			tcell.style.background = '#' + this.colors[i];

			anchor = document.createElement('a');
			anchor.href = '#';
			anchor.appendChild(text);

			YAHOO.util.Event.addListener(anchor, 'click', this.selectColor,
				this, true);

			tcell.appendChild(anchor);
		} else {
			YAHOO.util.Dom.addClass(tcell,
				'swat-simple-color-entry-palette-blank');

			tcell.appendChild(text);
		}

		trow.appendChild(tcell);

		if ((i + 1) % this.columns == 0)
			tbody.appendChild(trow);
	}

	table.appendChild(tbody);
	this.palette.childNodes[1].appendChild(table);
}

SwatSimpleColorEntry.prototype.toggle = function()
{
	if (this.is_open)
		this.close();
	else
		this.open();
}

/**
 * Sets the value of the color entry input tag to the selected color and
 * highlights the selected color
 *
 * @param number color the hex value of the color
 */
SwatSimpleColorEntry.prototype.setColor = function(color)
{
	this.input_tag.value = color;

	if (color === null) {
		this.swatch.style.background = null;
	} else {
		this.hex_input_tag.value = color;
		this.swatch.style.background = '#' + color;
	}

	var changed = (this.current_color != color);

	if (changed) {
		this.current_color = color;

		if (color === null)
			this.colorChangeEvent.fire(null);
		else
			this.colorChangeEvent.fire('#' + color);

		this.highlightPalleteEntry(color);
	}
}

/**
 * Event handler that sets the color to the selected color
 *
 * @param Event the event that triggered this select.
 */
SwatSimpleColorEntry.prototype.selectColor = function(event)
{
	YAHOO.util.Event.preventDefault(event);
	var cell = YAHOO.util.Event.getTarget(event);
	var color_index = cell.parentNode.id.split('_palette_')[1];

	this.setColor(this.colors[color_index]);

	var palette_entry =
		document.getElementById(this.id + '_palette_' + color_index);

	this.close();
}

/**
 * Highlights a pallete entry
 *
 * @param number color the hex value of the color
 */
SwatSimpleColorEntry.prototype.highlightPalleteEntry = function(color)
{
	for (var i = 0; i < this.colors.length; i++) {
		var palette_entry =
			document.getElementById(this.id + '_palette_' + i);

		if (this.current_color !== null &&
			this.colors[i].toLowerCase() ==
			this.current_color.toLowerCase()) {

			YAHOO.util.Dom.addClass(palette_entry,
				'swat-simple-color-entry-palette-selected');
		} else {
			YAHOO.util.Dom.removeClass(palette_entry,
				'swat-simple-color-entry-palette-selected');
		}
	}
}

<commit_msg>Don't close the color entry after selecting a color from the palette.<commit_after>/**
 * Simple color entry widget
 *
 * @copyright 2005-2010 silverorange Inc.
 */

/**
 * Creates a SwatSimpleColorEntry object
 *
 * @param string id
 * @param Array colors
 */
function SwatSimpleColorEntry(id, colors)
{
	this.id = id;
	this.colors = colors;
	this.is_open = false;
	this.is_drawn = false;
	this.is_positioned = false;

	this.input_tag = document.getElementById(this.id + '_value');
	this.swatch = document.getElementById(this.id + '_swatch');

	this.hex_input_tag = document.createElement('input');
	this.hex_input_tag.type = 'text';
	this.hex_input_tag.id = this.id + '_hex_color';
	this.hex_input_tag.size = 6;

	YAHOO.util.Event.addListener(this.hex_input_tag, 'change',
		this.handleInputChange, this, true);

	YAHOO.util.Event.addListener(this.hex_input_tag, 'keyup',
		this.handleInputChange, this, true);

	// this tries to make a square palette
	this.columns = Math.ceil(Math.sqrt(this.colors.length));

	this.current_color = null;
	this.colorChangeEvent = new YAHOO.util.CustomEvent('colorChange');

	this.setColor(this.input_tag.value);

	this.drawButton();
	this.drawPalette();
	this.drawInput();

	YAHOO.util.Event.onContentReady(this.id + '_palette',
		this.createOverlay, this, true)
}

SwatSimpleColorEntry.set_text = 'Set';

/**
 * Displays the toggle button for this simple color entry
 */
SwatSimpleColorEntry.prototype.drawButton = function()
{
	this.toggle_button = document.createElement('button');
	YAHOO.util.Dom.addClass(this.toggle_button,
		'swat-simple-color-entry-toggle-button');

	// the type property is readonly in IE so use setAttribute() here
	this.toggle_button.setAttribute('type', 'button');

	this.swatch.parentNode.replaceChild(this.toggle_button, this.swatch);
	this.toggle_button.appendChild(this.swatch);
	YAHOO.util.Event.addListener(this.toggle_button, 'click', this.toggle,
		this, true);

	this.palette = document.createElement('div');
	this.palette.id = this.id + '_palette';
	YAHOO.util.Dom.addClass(this.palette, 'swat-simple-color-entry-palette');
	this.palette.style.display = 'none';

	var overlay_header = document.createElement('div');
	YAHOO.util.Dom.addClass(overlay_header, 'hd');

	var overlay_body = document.createElement('div');
	YAHOO.util.Dom.addClass(overlay_body, 'bd');

	var overlay_footer = document.createElement('div');
	YAHOO.util.Dom.addClass(overlay_footer, 'ft');

	this.palette.appendChild(overlay_header);
	this.palette.appendChild(overlay_body);
	this.palette.appendChild(overlay_footer);

	var container = document.getElementById(this.id);
	container.appendChild(this.palette);
}

/**
 * Creates simple color entry overlay widget when toggle button has been drawn
 */
SwatSimpleColorEntry.prototype.createOverlay = function(event)
{
	this.overlay = new YAHOO.widget.Overlay(this.id + '_palette',
		{ visible: false, constraintoviewport: true });

	this.overlay.render(document.body);
	this.palette.style.display = 'block';
	this.is_drawn = true;
}

/**
 * Closes this color palette
 */
SwatSimpleColorEntry.prototype.close = function()
{
	this.overlay.hide();
	SwatZIndexManager.lowerElement(this.palette);
	this.is_open = false;
}

/**
 * Opens this color palette
 */
SwatSimpleColorEntry.prototype.open = function()
{
	if (!this.is_positioned) {
		this.overlay.cfg.setProperty('context',
			[this.toggle_button, 'tl', 'bl']);

		this.is_positioned = true;
	}

	this.overlay.show();
	SwatZIndexManager.raiseElement(this.palette);
	this.is_open = true;
}

/**
 * Draws the hex input box
 */
SwatSimpleColorEntry.prototype.drawInput = function()
{
	var div_tag = document.createElement('div');
	div_tag.className = 'swat-simple-color-entry-palette-hex-color';

	var label_tag = document.createElement('label');
	label_tag.htmlFor = this.id + '_hex_color';
	var title = document.createTextNode('#');
	label_tag.appendChild(title);

	var button_tag = document.createElement('button');
	button_tag.setAttribute('type', 'button');
	var title = document.createTextNode(SwatSimpleColorEntry.set_text);
	button_tag.appendChild(title);
	YAHOO.util.Event.addListener(button_tag, 'click', this.toggle, this, true);

	div_tag.appendChild(label_tag);
	div_tag.appendChild(this.hex_input_tag);
	div_tag.appendChild(button_tag);

	this.palette.childNodes[1].appendChild(div_tag);
}

SwatSimpleColorEntry.prototype.handleInputChange = function()
{
	var color = this.hex_input_tag.value;

	if (color[0] == '#') {
		color = color.slice(1, color.length - 1);
	}

	if (color.length == 3) {
		var hex3 = /^[0-9a-f]{3}$/i;
		if (!hex3.test(color)) {
			color = null;
		}
	} else if (color.length == 6) {
		var hex6 = /^[0-9a-f]{6}$/i;
		if (!hex6.test(color)) {
			color = null;
		}
	} else {
		color = null;
	}

	this.setColor(color);
}

/**
 * Draws this color palette
 */
SwatSimpleColorEntry.prototype.drawPalette = function()
{
	var table = document.createElement('table');
	table.cellSpacing = '1';

	var tbody = document.createElement('tbody');

	if (this.colors.length % this.columns == 0)
		var num_cells = this.colors.length
	else
		var num_cells = this.colors.length +
			(this.columns - (this.colors.length % this.columns));

	var trow;
	var tcell;
	var anchor;
	var text;

	for (var i = 0; i < num_cells; i++) {
		if (i % this.columns == 0)
			trow = document.createElement('tr');

		tcell = document.createElement('td');
		text = document.createTextNode(' '); // non-breaking UTF-8 space

		if (i < this.colors.length) {
			tcell.id = this.id + '_palette_' + i;
			tcell.style.background = '#' + this.colors[i];

			anchor = document.createElement('a');
			anchor.href = '#';
			anchor.appendChild(text);

			YAHOO.util.Event.addListener(anchor, 'click', this.selectColor,
				this, true);

			tcell.appendChild(anchor);
		} else {
			YAHOO.util.Dom.addClass(tcell,
				'swat-simple-color-entry-palette-blank');

			tcell.appendChild(text);
		}

		trow.appendChild(tcell);

		if ((i + 1) % this.columns == 0)
			tbody.appendChild(trow);
	}

	table.appendChild(tbody);
	this.palette.childNodes[1].appendChild(table);
}

SwatSimpleColorEntry.prototype.toggle = function()
{
	if (this.is_open)
		this.close();
	else
		this.open();
}

/**
 * Sets the value of the color entry input tag to the selected color and
 * highlights the selected color
 *
 * @param number color the hex value of the color
 */
SwatSimpleColorEntry.prototype.setColor = function(color)
{
	this.input_tag.value = color;

	if (color === null) {
		this.swatch.style.background = null;
	} else {
		this.hex_input_tag.value = color;
		this.swatch.style.background = '#' + color;
	}

	var changed = (this.current_color != color);

	if (changed) {
		this.current_color = color;

		if (color === null)
			this.colorChangeEvent.fire(null);
		else
			this.colorChangeEvent.fire('#' + color);

		this.highlightPalleteEntry(color);
	}
}

/**
 * Event handler that sets the color to the selected color
 *
 * @param Event the event that triggered this select.
 */
SwatSimpleColorEntry.prototype.selectColor = function(event)
{
	YAHOO.util.Event.preventDefault(event);
	var cell = YAHOO.util.Event.getTarget(event);
	var color_index = cell.parentNode.id.split('_palette_')[1];

	this.setColor(this.colors[color_index]);

	var palette_entry =
		document.getElementById(this.id + '_palette_' + color_index);
}

/**
 * Highlights a pallete entry
 *
 * @param number color the hex value of the color
 */
SwatSimpleColorEntry.prototype.highlightPalleteEntry = function(color)
{
	for (var i = 0; i < this.colors.length; i++) {
		var palette_entry =
			document.getElementById(this.id + '_palette_' + i);

		if (this.current_color !== null &&
			this.colors[i].toLowerCase() ==
			this.current_color.toLowerCase()) {

			YAHOO.util.Dom.addClass(palette_entry,
				'swat-simple-color-entry-palette-selected');
		} else {
			YAHOO.util.Dom.removeClass(palette_entry,
				'swat-simple-color-entry-palette-selected');
		}
	}
}

<|endoftext|>


<commit_before>// {{{ function SwatSimpleColorEntry

/**
 * Simple color entry widget
 *
 * @param string id
 * @param Array colors
 * @param string none_option_title
 *
 * @copyright 2005-2010 silverorange Inc.
 */

function SwatSimpleColorEntry(id, colors, none_option_title)
{
	SwatSimpleColorEntry.superclass.constructor.call(this, id);

	this.colors = colors;
	this.none_option_title = none_option_title;
	this.input_tag = document.getElementById(this.id + '_value');

	this.hex_input_tag = document.createElement('input');
	this.hex_input_tag.type = 'text';
	this.hex_input_tag.id = this.id + '_hex_color';
	this.hex_input_tag.size = 6;

	YAHOO.util.Event.on(this.hex_input_tag, 'change',
		this.handleInputChange, this, true);

	YAHOO.util.Event.on(this.hex_input_tag, 'keyup',
		this.handleInputChange, this, true);

	// this tries to make a square palette
	this.columns = Math.ceil(Math.sqrt(this.colors.length));

	this.current_color = null;
	this.colorChangeEvent = new YAHOO.util.CustomEvent('colorChange');

	this.setColor(this.input_tag.value);
}

// }}}
// {{{ YAHOO.lang.extend(SwatSimpleColorEntry, SwatAbstractOverlay)

YAHOO.lang.extend(SwatSimpleColorEntry, SwatAbstractOverlay, {
// {{{ getContent: function()

getContent: function()
{
	var table = document.createElement('table');
	table.className = 'swat-simple-color-entry-table';
	table.cellSpacing = '1';

	var tbody = document.createElement('tbody');

	if (this.colors.length % this.columns == 0)
		var num_cells = this.colors.length
	else
		var num_cells = this.colors.length +
			(this.columns - (this.colors.length % this.columns));

	var trow;
	var tcell;
	var anchor;
	var text;

	if (this.none_option_title !== null) {
		trow = document.createElement('tr');
		tcell = document.createElement('td');
		tcell.id = this.id + '_palette_null';
		tcell.colSpan = this.columns;
		YAHOO.util.Dom.addClass(tcell,
			'swat-simple-color-entry-palette-blank');

		text = document.createTextNode(this.none_option_title);

		anchor = document.createElement('a');
		anchor.href = '#';
		anchor.appendChild(text);
		tcell.appendChild(anchor);
		trow.appendChild(tcell);
		tbody.appendChild(trow);

		YAHOO.util.Event.addListener(anchor, 'click', this.selectNull,
			this, true);
	}

	for (var i = 0; i < num_cells; i++) {
		if (i % this.columns == 0)
			trow = document.createElement('tr');

		tcell = document.createElement('td');
		text = document.createTextNode(' '); // non-breaking UTF-8 space

		if (i < this.colors.length) {
			tcell.id = this.id + '_palette_' + i;
			tcell.style.background = '#' + this.colors[i];

			anchor = document.createElement('a');
			anchor.href = '#';
			anchor.appendChild(text);

			YAHOO.util.Event.addListener(anchor, 'click', this.selectColor,
				this, true);

			tcell.appendChild(anchor);
		} else {
			YAHOO.util.Dom.addClass(tcell,
				'swat-simple-color-entry-palette-blank');

			tcell.appendChild(text);
		}

		trow.appendChild(tcell);

		if ((i + 1) % this.columns == 0)
			tbody.appendChild(trow);
	}

	table.appendChild(tbody);

	var hex_div = document.createElement('div');
	hex_div.className = 'swat-simple-color-entry-palette-hex-color';

	var label_tag = document.createElement('label');
	label_tag.htmlFor = this.id + '_hex_color';
	var title = document.createTextNode('#');
	label_tag.appendChild(title);

	hex_div.appendChild(label_tag);
	hex_div.appendChild(this.hex_input_tag);

	var div_tag = document.createElement('div');
	div_tag.appendChild(table);
	div_tag.appendChild(hex_div);

	return div_tag;
}

// }}}
});

// }}}
// {{{ SwatSimpleColorEntry.prototype.handleInputChange

SwatSimpleColorEntry.prototype.handleInputChange = function()
{
	var color = this.hex_input_tag.value;

	if (color[0] == '#') {
		color = color.slice(1, color.length - 1);
	}

	if (color.length == 3) {
		var hex3 = /^[0-9a-f]{3}$/i;
		if (!hex3.test(color)) {
			color = null;
		}
	} else if (color.length == 6) {
		var hex6 = /^[0-9a-f]{6}$/i;
		if (!hex6.test(color)) {
			color = null;
		}
	} else {
		color = null;
	}

	this.setColor(color);
}

// }}}
// {{{ SwatSimpleColorEntry.prototype.setColor

/**
 * Sets the value of the color entry input tag to the selected color and
 * highlights the selected color
 *
 * @param number color the hex value of the color
 */
SwatSimpleColorEntry.prototype.setColor = function(color)
{
	if (!/^([0-9a-f]{3}){1,2}$/i.test(color)) {
		color = null;
	}

	var changed = (this.current_color != color);

	if (changed) {
		this.input_tag.value = color;

		if (color === null) {
			YAHOO.util.Dom.setStyle(this.toggle_button_content,
				'background', '');
		} else {
			if (this.hex_input_tag.value != color) {
				this.hex_input_tag.value = color;
			}
			YAHOO.util.Dom.setStyle(this.toggle_button_content,
				'background', '#' + color);
		}

		this.current_color = color;

		this.value_field.value = color;

		if (color === null) {
			this.colorChangeEvent.fire(null);
		} else {
			this.colorChangeEvent.fire('#' + color);
		}

		this.highlightPalleteEntry(color);
	}
}

// }}}
// {{{ SwatSimpleColorEntry.prototype.selectNull

/**
 * Event handler that sets the color to null
 *
 * @param Event the event that triggered this select.
 */
SwatSimpleColorEntry.prototype.selectNull = function(event)
{
	this.hex_input_tag.value = '';
	YAHOO.util.Event.preventDefault(event);
	this.setColor(null);
}

// }}}
// {{{ SwatSimpleColorEntry.prototype.selectColor

/**
 * Event handler that sets the color to the selected color
 *
 * @param Event the event that triggered this select.
 */
SwatSimpleColorEntry.prototype.selectColor = function(event)
{
	YAHOO.util.Event.preventDefault(event);
	var cell = YAHOO.util.Event.getTarget(event);
	var color_index = cell.parentNode.id.split('_palette_')[1];

	this.setColor(this.colors[color_index]);
}

// }}}
// {{{ SwatSimpleColorEntry.prototype.highlightPalleteEntry

/**
 * Highlights a pallete entry
 *
 * @param number color the hex value of the color
 */
SwatSimpleColorEntry.prototype.highlightPalleteEntry = function(color)
{
	if (this.none_option_title !== null) {
		var null_entry = document.getElementById(this.id + '_palette_null');

		if (color === null) {
			YAHOO.util.Dom.addClass(null_entry,
				'swat-simple-color-entry-palette-selected');
		} else {
			YAHOO.util.Dom.removeClass(null_entry,
				'swat-simple-color-entry-palette-selected');
		}
	}

	for (var i = 0; i < this.colors.length; i++) {
		var palette_entry =
			document.getElementById(this.id + '_palette_' + i);

		if (this.current_color !== null &&
			this.colors[i].toLowerCase() ==
			this.current_color.toLowerCase()) {

			YAHOO.util.Dom.addClass(palette_entry,
				'swat-simple-color-entry-palette-selected');
		} else {
			YAHOO.util.Dom.removeClass(palette_entry,
				'swat-simple-color-entry-palette-selected');
		}
	}
}

// }}}
<commit_msg>Fix HTTP POST value of 'null' in IE and fix setting null background image in IE.<commit_after>// {{{ function SwatSimpleColorEntry

/**
 * Simple color entry widget
 *
 * @param string id
 * @param Array colors
 * @param string none_option_title
 *
 * @copyright 2005-2010 silverorange Inc.
 */

function SwatSimpleColorEntry(id, colors, none_option_title)
{
	SwatSimpleColorEntry.superclass.constructor.call(this, id);

	this.colors = colors;
	this.none_option_title = none_option_title;
	this.input_tag = document.getElementById(this.id + '_value');

	this.hex_input_tag = document.createElement('input');
	this.hex_input_tag.type = 'text';
	this.hex_input_tag.id = this.id + '_hex_color';
	this.hex_input_tag.size = 6;

	YAHOO.util.Event.on(this.hex_input_tag, 'change',
		this.handleInputChange, this, true);

	YAHOO.util.Event.on(this.hex_input_tag, 'keyup',
		this.handleInputChange, this, true);

	// this tries to make a square palette
	this.columns = Math.ceil(Math.sqrt(this.colors.length));

	this.current_color = null;
	this.colorChangeEvent = new YAHOO.util.CustomEvent('colorChange');

	this.setColor(this.input_tag.value);
}

// }}}
// {{{ YAHOO.lang.extend(SwatSimpleColorEntry, SwatAbstractOverlay)

YAHOO.lang.extend(SwatSimpleColorEntry, SwatAbstractOverlay, {
// {{{ getContent: function()

getContent: function()
{
	var table = document.createElement('table');
	table.className = 'swat-simple-color-entry-table';
	table.cellSpacing = '1';

	var tbody = document.createElement('tbody');

	if (this.colors.length % this.columns == 0)
		var num_cells = this.colors.length
	else
		var num_cells = this.colors.length +
			(this.columns - (this.colors.length % this.columns));

	var trow;
	var tcell;
	var anchor;
	var text;

	if (this.none_option_title !== null) {
		trow = document.createElement('tr');
		tcell = document.createElement('td');
		tcell.id = this.id + '_palette_null';
		tcell.colSpan = this.columns;
		YAHOO.util.Dom.addClass(tcell,
			'swat-simple-color-entry-palette-blank');

		text = document.createTextNode(this.none_option_title);

		anchor = document.createElement('a');
		anchor.href = '#';
		anchor.appendChild(text);
		tcell.appendChild(anchor);
		trow.appendChild(tcell);
		tbody.appendChild(trow);

		YAHOO.util.Event.addListener(anchor, 'click', this.selectNull,
			this, true);
	}

	for (var i = 0; i < num_cells; i++) {
		if (i % this.columns == 0)
			trow = document.createElement('tr');

		tcell = document.createElement('td');
		text = document.createTextNode(' '); // non-breaking UTF-8 space

		if (i < this.colors.length) {
			tcell.id = this.id + '_palette_' + i;
			tcell.style.background = '#' + this.colors[i];

			anchor = document.createElement('a');
			anchor.href = '#';
			anchor.appendChild(text);

			YAHOO.util.Event.addListener(anchor, 'click', this.selectColor,
				this, true);

			tcell.appendChild(anchor);
		} else {
			YAHOO.util.Dom.addClass(tcell,
				'swat-simple-color-entry-palette-blank');

			tcell.appendChild(text);
		}

		trow.appendChild(tcell);

		if ((i + 1) % this.columns == 0)
			tbody.appendChild(trow);
	}

	table.appendChild(tbody);

	var hex_div = document.createElement('div');
	hex_div.className = 'swat-simple-color-entry-palette-hex-color';

	var label_tag = document.createElement('label');
	label_tag.htmlFor = this.id + '_hex_color';
	var title = document.createTextNode('#');
	label_tag.appendChild(title);

	hex_div.appendChild(label_tag);
	hex_div.appendChild(this.hex_input_tag);

	var div_tag = document.createElement('div');
	div_tag.appendChild(table);
	div_tag.appendChild(hex_div);

	return div_tag;
}

// }}}
});

// }}}
// {{{ SwatSimpleColorEntry.prototype.handleInputChange

SwatSimpleColorEntry.prototype.handleInputChange = function()
{
	var color = this.hex_input_tag.value;

	if (color[0] == '#') {
		color = color.slice(1, color.length - 1);
	}

	if (color.length == 3) {
		var hex3 = /^[0-9a-f]{3}$/i;
		if (!hex3.test(color)) {
			color = null;
		}
	} else if (color.length == 6) {
		var hex6 = /^[0-9a-f]{6}$/i;
		if (!hex6.test(color)) {
			color = null;
		}
	} else {
		color = null;
	}

	this.setColor(color);
}

// }}}
// {{{ SwatSimpleColorEntry.prototype.setColor

/**
 * Sets the value of the color entry input tag to the selected color and
 * highlights the selected color
 *
 * @param number color the hex value of the color
 */
SwatSimpleColorEntry.prototype.setColor = function(color)
{
	if (!/^([0-9a-f]{3}){1,2}$/i.test(color)) {
		color = null;
	}

	var changed = (this.current_color != color);

	if (changed) {
		if (color === null) {
			// IE fix, it sets string 'null' otherwise
			this.input_tag.value = '';
		} else {
			this.input_tag.value = color;
		}

		if (color === null) {
			if (this.hex_input_tag.value != '') {
				// IE fix, it sets string 'null' otherwise
				this.hex_input_tag.value = '';
			}
			YAHOO.util.Dom.setStyle(this.toggle_button_content,
				'background', 'url(packages/swat/images/color-entry-null.png)');
		} else {
			if (this.hex_input_tag.value != color) {
				this.hex_input_tag.value = color;
			}
			YAHOO.util.Dom.setStyle(this.toggle_button_content,
				'background', '#' + color);
		}

		this.current_color = color;

		if (color === null) {
			this.colorChangeEvent.fire(null);
		} else {
			this.colorChangeEvent.fire('#' + color);
		}

		this.highlightPalleteEntry(color);
	}
}

// }}}
// {{{ SwatSimpleColorEntry.prototype.selectNull

/**
 * Event handler that sets the color to null
 *
 * @param Event the event that triggered this select.
 */
SwatSimpleColorEntry.prototype.selectNull = function(e)
{
	YAHOO.util.Event.preventDefault(e);
	this.setColor(null);
}

// }}}
// {{{ SwatSimpleColorEntry.prototype.selectColor

/**
 * Event handler that sets the color to the selected color
 *
 * @param Event the event that triggered this select.
 */
SwatSimpleColorEntry.prototype.selectColor = function(event)
{
	YAHOO.util.Event.preventDefault(event);
	var cell = YAHOO.util.Event.getTarget(event);
	var color_index = cell.parentNode.id.split('_palette_')[1];

	this.setColor(this.colors[color_index]);
}

// }}}
// {{{ SwatSimpleColorEntry.prototype.highlightPalleteEntry

/**
 * Highlights a pallete entry
 *
 * @param number color the hex value of the color
 */
SwatSimpleColorEntry.prototype.highlightPalleteEntry = function(color)
{
	if (this.none_option_title !== null) {
		var null_entry = document.getElementById(this.id + '_palette_null');

		if (color === null) {
			YAHOO.util.Dom.addClass(null_entry,
				'swat-simple-color-entry-palette-selected');
		} else {
			YAHOO.util.Dom.removeClass(null_entry,
				'swat-simple-color-entry-palette-selected');
		}
	}

	for (var i = 0; i < this.colors.length; i++) {
		var palette_entry =
			document.getElementById(this.id + '_palette_' + i);

		if (this.current_color !== null &&
			this.colors[i].toLowerCase() ==
			this.current_color.toLowerCase()) {

			YAHOO.util.Dom.addClass(palette_entry,
				'swat-simple-color-entry-palette-selected');
		} else {
			YAHOO.util.Dom.removeClass(palette_entry,
				'swat-simple-color-entry-palette-selected');
		}
	}
}

// }}}
<|endoftext|>