<commit_before>var RELOAD_INTERVAL = 5;  // seconds

var Comments = (function() {

    var since = null;
    var halt_reload_loop = false;
    var pause_reload_loop = false;

    function approve_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            approve: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                $('a.action-approve', parent).hide();
                $('.not-approved', parent).fadeOut(300);
                $('a.action-unapprove', parent).show();
            } else {
                alert("Sorry. Unable to approve this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to approve this. Please try again later.");
        });
    }

    function unapprove_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            unapprove: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                $('a.action-approve', parent).show();
                $('a.action-unapprove', parent).hide();
                $('.not-approved', parent).fadeIn(300);
            } else {
                alert("Sorry. Unable to unapprove this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to approve this. Please try again later.");
        });
    }

    function remove_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            remove: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                parent.fadeTo(200, 0.1, function() {
                    $(this).html('Comment removed').addClass('removed-pending').fadeTo(100, 1.0);
                    setTimeout(function() {
                        $('.removed-pending').fadeOut(500).remove();
                    }, 5 * 1000);
                });
            } else {
                alert("Sorry. Unable to remove this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to remove this. Please try again later.");
        });
    }

    function flag_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            flag: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                $('a.action-flag', parent).hide();
                $('a.action-unflag', parent).show();
                $('.flagged-by-user', parent).show();
                $('.flagged', parent).fadeIn(300);
            } else {
                alert("Sorry. Unable to flag this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to flag this. Please try again later.");
        });
    }

    function unflag_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            unflag: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                $('a.action-unflag', parent).hide();
                $('.unflagged-by-user', parent).show();
                $('.flagged', parent).fadeOut(300);
            } else {
                alert("Sorry. Unable to unflag this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to unflag this. Please try again later.");
        });
    }

    return {
        load: function(container, callback) {
            var req = $.getJSON(container.data('url'));
            req.then(function(response) {
                if (!response.discussion.enabled) {
                    container.remove();
                    console.log('Discussion not enabled on this page');
                    return;
                }
                since = response.latest_comment;
                $('.comments-outer', container).html(response.html).show();
                $('time.timeago', container).timeago();
                $('a.permalink', container).click(function() {
                    $(this).closest('.comment').addClass('focus-on');
                    setTimeout(function() {
                        $('.focus-on').removeClass('focus-on');
                    }, 500);
                });
                $('a.action-reply', container).click(function() {
                    var parent = $(this).closest('.comment');
                    $('form input[name="reply_to"]', container).val(parent.data('id'));
                    // put the comment form under this
                    var comment_container = $(this).closest('.comment');
                    $('form', container).detach().appendTo(comment_container);
                    $('form button.cancel', container).show();
                    return false;
                });
                $('a.action-approve', container).click(function() {
                    approve_comment(this, container);
                    return false;
                });
                $('a.action-unapprove', container).click(function() {
                    unapprove_comment(this, container);
                    return false;
                });
                $('a.action-remove', container).click(function() {
                    remove_comment(this, container);
                    return false;
                });
                $('a.action-flag', container).click(function() {
                    flag_comment(this, container);
                    return false;
                });
                $('a.action-unflag', container).click(function() {
                    unflag_comment(this, container);
                    return false;
                });
                $('.failed-loading:visible', container).hide();
                if (callback) callback();
            });
            req.fail(function() {
                $('.failed-loading', container).fadeIn(300);
            });
            req.always(function() {
                $('.loading', container).remove();
            });
        },
        reload_loop: function(container) {
            if (halt_reload_loop || pause_reload_loop) {
                return;
            }
            var data = {since: since};
            var req = $.getJSON(container.data('reload-url'), data);
            req.then(function(response) {
                if (response.latest_comment) {
                    since = response.latest_comment;
                    Comments.load(container);
                }
            });
            req.fail(function() {
                console.warn('Error checking latest, so halt');
                halt_reload_loop = true;
            });
        },
        pause_loop: function() {
            pause_reload_loop = true;
        },
        resume_loop: function() {
            pause_reload_loop = false;
        }
    };
})();

(function(window, $) {
    "use strict";

    $(function() {
        var container = $('#comments');
        if (!container.length) {
            console.log('No #comments container on this page');
            return;
        }
        if (!$('input[name="name"]', container).val()) {
            // fetch the name async
            var element = $('input[name="name"]', container);
            $.getJSON(element.data('url')).then(function(response) {
                if (response.name) {
                    element.val(response.name);
                }
            });
        }
        Comments.load(container, function() {
            if (location.hash && location.hash.search(/#comment-\d+/) > -1) {
                // we should find a permalink with this href
                $('a.permalink', container).each(function(i, each) {
                    if ($(each).attr('href') === location.hash) {
                        var $parent = $(each).closest('.comment').addClass('focus-on');
                        $('html, body').animate({scrollTop: $parent.position().top}, "slow", function() {
                            $('.focus-on').removeClass('focus-on');
                        });
                    }
                });
            }
            setInterval(function() {
                Comments.reload_loop(container);
            }, 5 * 1000);
        });

        $('button.cancel', container).click(function() {
            $(this).hide();
            $('form', container).detach().insertAfter($('.comments-outer', container));
            $('form input[name="reply_to"]', container).val('');
            return false;
        });

        $('form textarea', container).on('focus', function() {
            Comments.pause_loop();
        }).on('blur', function() {
            Comments.resume_loop();
        });

        $('form', container).submit(function() {
            var $form = $(this);
            var comment = $.trim($('textarea[name="comment"]', this).val());
            if (!comment) return false;
            var data = {
                comment: comment,
                name: $('input[name="name"]', this).val(),
                reply_to: $('input[name="reply_to"]', this).val(),
                csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', this).val()
            };
            // We don't want to run the reload loop whilst waiting for the submission post
            Comments.pause_loop();
            var req = $.post(container.data('url'), data);
            req.done(function(response) {
                $('form').data('changes', 0);
                $('textarea[name="comment"]', $form).val('');
                $('.submission-success', $form).show();
                $('form button.cancel:visible', container).click();
                Comments.load(container);
                setTimeout(function() {
                    $('.submission-success', $form).fadeOut(600);
                }, RELOAD_INTERVAL * 1000);
            });
            req.always(function() {
                $('button[type="submit"]').removeProp('disabled');
                Comments.resume_loop();
            });
            req.fail(function(jqXHR, textStatus, errorThrown) {
                console.log('jqXHR', jqXHR);
                console.log('textStatus', textStatus);
                console.log('errorThrown', errorThrown);
                $('.other-error', container).show();
            });
            return false;
        });

    });

})(window, $);
<commit_msg>fixes bug 996136 - Clicking "Reply" on comment should set focus in textarea<commit_after>var RELOAD_INTERVAL = 5;  // seconds

var Comments = (function() {

    var since = null;
    var halt_reload_loop = false;
    var pause_reload_loop = false;

    function approve_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            approve: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                $('a.action-approve', parent).hide();
                $('.not-approved', parent).fadeOut(300);
                $('a.action-unapprove', parent).show();
            } else {
                alert("Sorry. Unable to approve this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to approve this. Please try again later.");
        });
    }

    function unapprove_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            unapprove: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                $('a.action-approve', parent).show();
                $('a.action-unapprove', parent).hide();
                $('.not-approved', parent).fadeIn(300);
            } else {
                alert("Sorry. Unable to unapprove this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to approve this. Please try again later.");
        });
    }

    function remove_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            remove: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                parent.fadeTo(200, 0.1, function() {
                    $(this).html('Comment removed').addClass('removed-pending').fadeTo(100, 1.0);
                    setTimeout(function() {
                        $('.removed-pending').fadeOut(500).remove();
                    }, 5 * 1000);
                });
            } else {
                alert("Sorry. Unable to remove this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to remove this. Please try again later.");
        });
    }

    function flag_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            flag: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                $('a.action-flag', parent).hide();
                $('a.action-unflag', parent).show();
                $('.flagged-by-user', parent).show();
                $('.flagged', parent).fadeIn(300);
            } else {
                alert("Sorry. Unable to flag this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to flag this. Please try again later.");
        });
    }

    function unflag_comment(clicked, container) {
        var parent = $(clicked).closest('.comment');
        var data = {
            unflag: parent.data('id'),
            csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', container).val()
        };
        var req = $.post(container.data('url'), data);
        req.done(function(response) {
            if (response.ok) {
                $('a.action-unflag', parent).hide();
                $('.unflagged-by-user', parent).show();
                $('.flagged', parent).fadeOut(300);
            } else {
                alert("Sorry. Unable to unflag this comment at the moment.");
            }
        });
        req.fail(function() {
            alert("Sorry. An error happened trying to unflag this. Please try again later.");
        });
    }

    return {
        load: function(container, callback) {
            var req = $.getJSON(container.data('url'));
            req.then(function(response) {
                if (!response.discussion.enabled) {
                    container.remove();
                    console.log('Discussion not enabled on this page');
                    return;
                }
                since = response.latest_comment;
                $('.comments-outer', container).html(response.html).show();
                $('time.timeago', container).timeago();
                $('a.permalink', container).click(function() {
                    $(this).closest('.comment').addClass('focus-on');
                    setTimeout(function() {
                        $('.focus-on').removeClass('focus-on');
                    }, 500);
                });
                $('a.action-reply', container).click(function() {
                    var parent = $(this).closest('.comment');
                    $('form input[name="reply_to"]', container).val(parent.data('id'));
                    // put the comment form under this
                    var comment_container = $(this).closest('.comment');
                    $('form', container).detach().appendTo(comment_container);
                    $('form button.cancel', container).show();
                    $('textarea', container).focus();
                    return false;
                });
                $('a.action-approve', container).click(function() {
                    approve_comment(this, container);
                    return false;
                });
                $('a.action-unapprove', container).click(function() {
                    unapprove_comment(this, container);
                    return false;
                });
                $('a.action-remove', container).click(function() {
                    remove_comment(this, container);
                    return false;
                });
                $('a.action-flag', container).click(function() {
                    flag_comment(this, container);
                    return false;
                });
                $('a.action-unflag', container).click(function() {
                    unflag_comment(this, container);
                    return false;
                });
                $('.failed-loading:visible', container).hide();
                if (callback) callback();
            });
            req.fail(function() {
                $('.failed-loading', container).fadeIn(300);
            });
            req.always(function() {
                $('.loading', container).remove();
            });
        },
        reload_loop: function(container) {
            if (halt_reload_loop || pause_reload_loop) {
                return;
            }
            var data = {since: since};
            var req = $.getJSON(container.data('reload-url'), data);
            req.then(function(response) {
                if (response.latest_comment) {
                    since = response.latest_comment;
                    Comments.load(container);
                }
            });
            req.fail(function() {
                console.warn('Error checking latest, so halt');
                halt_reload_loop = true;
            });
        },
        pause_loop: function() {
            pause_reload_loop = true;
        },
        resume_loop: function() {
            pause_reload_loop = false;
        }
    };
})();

(function(window, $) {
    "use strict";

    $(function() {
        var container = $('#comments');
        if (!container.length) {
            console.log('No #comments container on this page');
            return;
        }
        if (!$('input[name="name"]', container).val()) {
            // fetch the name async
            var element = $('input[name="name"]', container);
            $.getJSON(element.data('url')).then(function(response) {
                if (response.name) {
                    element.val(response.name);
                }
            });
        }
        Comments.load(container, function() {
            if (location.hash && location.hash.search(/#comment-\d+/) > -1) {
                // we should find a permalink with this href
                $('a.permalink', container).each(function(i, each) {
                    if ($(each).attr('href') === location.hash) {
                        var $parent = $(each).closest('.comment').addClass('focus-on');
                        $('html, body').animate({scrollTop: $parent.position().top}, "slow", function() {
                            $('.focus-on').removeClass('focus-on');
                        });
                    }
                });
            }
            setInterval(function() {
                Comments.reload_loop(container);
            }, 5 * 1000);
        });

        $('button.cancel', container).click(function() {
            $(this).hide();
            $('form', container).detach().insertAfter($('.comments-outer', container));
            $('form input[name="reply_to"]', container).val('');
            return false;
        });

        $('form textarea', container).on('focus', function() {
            Comments.pause_loop();
        }).on('blur', function() {
            Comments.resume_loop();
        });

        $('form', container).submit(function() {
            var $form = $(this);
            var comment = $.trim($('textarea[name="comment"]', this).val());
            if (!comment) return false;
            var data = {
                comment: comment,
                name: $('input[name="name"]', this).val(),
                reply_to: $('input[name="reply_to"]', this).val(),
                csrfmiddlewaretoken: $('input[name="csrfmiddlewaretoken"]', this).val()
            };
            // We don't want to run the reload loop whilst waiting for the submission post
            Comments.pause_loop();
            var req = $.post(container.data('url'), data);
            req.done(function(response) {
                $('form').data('changes', 0);
                $('textarea[name="comment"]', $form).val('');
                $('.submission-success', $form).show();
                $('form button.cancel:visible', container).click();
                Comments.load(container);
                setTimeout(function() {
                    $('.submission-success', $form).fadeOut(600);
                }, RELOAD_INTERVAL * 1000);
            });
            req.always(function() {
                $('button[type="submit"]').removeProp('disabled');
                Comments.resume_loop();
            });
            req.fail(function(jqXHR, textStatus, errorThrown) {
                console.warn('jqXHR', jqXHR);
                console.warn('textStatus', textStatus);
                console.warn('errorThrown', errorThrown);
                $('.other-error', container).show();
            });
            return false;
        });

    });

})(window, $);
<|endoftext|>


<commit_before>angular.module('geoApp').directive('sortField', function () {
    return {
        restrict: 'AE',
        replace: true,
        template: '' +
                    '{{ name | translate}}{{predicate}}' +
                    '' +
                    '' +
                  '' ,
        scope: {
            name: '@',
            value: '@'

        },
        controller: ['$scope','$translate', function ($scope,$translate) {
            function localizePredicate(predicate) {
                var tokens = predicate.split(",");
                if(tokens.length == 0) return predicate;
                var value_et = tokens[0], value_en = tokens[1];

                return $translate.use() == 'et' ? value_et : value_en;
            }

            $scope.order = function (predicate) {
                $scope.predicate = predicate;
                predicate = localizePredicate(predicate);
                $scope.$parent.sortByAsc = ($scope.$parent.searchParameters.sortField.sortBy === predicate ? !$scope.$parent.sortByAsc : true);
                $scope.$parent.searchParameters.sortField.sortBy = predicate;
                !$scope.$parent.sortByAsc ? $scope.$parent.searchParameters.sortField.order = "ASCENDING" : $scope.$parent.searchParameters.sortField.order = "DESCENDING";
                $scope.$parent.searchParameters.page = 1;
                $scope.$parent.search();
            };
        }]
    }
});<commit_msg>fixed small sort bug<commit_after>angular.module('geoApp').directive('sortField', function () {
    return {
        restrict: 'AE',
        replace: true,
        template: '' +
                    '{{ name | translate}}' +
                    '' +
                    '' +
                  '' ,
        scope: {
            name: '@',
            value: '@'

        },
        controller: ['$scope','$translate', function ($scope,$translate) {
            function localizePredicate(predicate) {
                var tokens = predicate.split(",");
                if(tokens.length == 0) return predicate;
                var value_et = tokens[0], value_en = tokens[1];

                return $translate.use() == 'et' ? value_et : value_en;
            }

            $scope.order = function (predicate) {
                $scope.predicate = predicate;
                predicate = localizePredicate(predicate);
                $scope.$parent.sortByAsc = ($scope.$parent.searchParameters.sortField.sortBy === predicate ? !$scope.$parent.sortByAsc : true);
                $scope.$parent.searchParameters.sortField.sortBy = predicate;
                !$scope.$parent.sortByAsc ? $scope.$parent.searchParameters.sortField.order = "ASCENDING" : $scope.$parent.searchParameters.sortField.order = "DESCENDING";
                $scope.$parent.searchParameters.page = 1;
                $scope.$parent.search();
            };
        }]
    }
});<|endoftext|>


<commit_before>import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import duration from "dayjs/plugin/duration";

export function formatInternationalizedDateTime(
  d,
  options = {
    hour: "numeric",
    minute: "numeric",
    year: "numeric",
    month: "short",
    day: "numeric",
  }
) {
  if (!isDate(d)) return "";
  return new Intl.DateTimeFormat(window.TL.LANGUAGE_TAG, options).format(
    new Date(d)
  );
}

/**
 * Generate the a human readable form from milliseconds.
 * @param {Number} date to format
 * @return {string} humanized version of the date
 */
export function getHumanizedDuration({ date }) {
  dayjs.extend(duration);
  dayjs.extend(relativeTime);
  return dayjs.duration(-date).humanize(false);
}

/**
 * Generate the time from now.  Renders as human readable.s
 * @param {number} date raw string date from server
 * @return {*}
 */
export function fromNow({ date }) {
  // Using dayjs because Intl.RelativeTimeFormat does not have browser
  // support in IE11 or safari yet.
  dayjs.extend(duration);
  dayjs.extend(relativeTime);
  const d1 = dayjs();
  const d2 = dayjs(date);
  return dayjs.duration(d2.diff(d1)).humanize(true);
}

/**
 * Format unix timestamp as human readable string.
 * @param  {(string | number)} date unix timestamp
 * @param {String} format defaults to "lll" which is mmm dd, YYYY h:mm AM
 * @return {string} formatted date
 */
export function formatDate({ date, format }) {
  return formatInternationalizedDateTime(date, format);
}

/**
 * Utility function to determine if a string is a date.
 * @param {(number | string)} date
 * @returns {boolean}
 */
export function isDate(date) {
  const d = new Date(date);
  return !isNaN(d.valueOf());
}

// get a readable string of the time from a given number of seconds
export function getDurationFromSeconds(seconds) {
  dayjs.extend(duration);
  dayjs.extend(relativeTime);
  return dayjs.duration(seconds * 1000).humanize(false);
}
<commit_msg>Removed undescriptive variables<commit_after>import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import duration from "dayjs/plugin/duration";

export function formatInternationalizedDateTime(
  d,
  options = {
    hour: "numeric",
    minute: "numeric",
    year: "numeric",
    month: "short",
    day: "numeric",
  }
) {
  if (!isDate(d)) return "";
  return new Intl.DateTimeFormat(window.TL.LANGUAGE_TAG, options).format(
    new Date(d)
  );
}

/**
 * Generate the a human readable form from milliseconds.
 * @param {Number} date to format
 * @return {string} humanized version of the date
 */
export function getHumanizedDuration({ date }) {
  dayjs.extend(duration);
  dayjs.extend(relativeTime);
  return dayjs.duration(-date).humanize(false);
}

/**
 * Generate the time from now.  Renders as human readable.s
 * @param {number} date raw string date from server
 * @return {*}
 */
export function fromNow({ date }) {
  // Using dayjs because Intl.RelativeTimeFormat does not have browser
  // support in IE11 or safari yet.
  dayjs.extend(duration);
  dayjs.extend(relativeTime);
  return dayjs.duration(dayjs(date).diff(dayjs())).humanize(true);
}

/**
 * Format unix timestamp as human readable string.
 * @param  {(string | number)} date unix timestamp
 * @param {String} format defaults to "lll" which is mmm dd, YYYY h:mm AM
 * @return {string} formatted date
 */
export function formatDate({ date, format }) {
  return formatInternationalizedDateTime(date, format);
}

/**
 * Utility function to determine if a string is a date.
 * @param {(number | string)} date
 * @returns {boolean}
 */
export const isDate = (date) => !isNaN(new Date(date).valueOf());

// get a readable string of the time from a given number of seconds
export function getDurationFromSeconds(seconds) {
  dayjs.extend(duration);
  dayjs.extend(relativeTime);
  return dayjs.duration(seconds * 1000).humanize(false);
}
<|endoftext|>


<commit_before>

<commit_msg>Deleted unecessary files.<commit_after><|endoftext|>


<commit_before>define([
  'angular',
  'lodash',
  'moment',
  'app/core/utils/kbn',
  './query_builder',
  './index_pattern',
  './elastic_response',
  './query_ctrl',
],
function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticResponse) {
  'use strict';

  /** @ngInject */
  function ElasticDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv) {
    this.basicAuth = instanceSettings.basicAuth;
    this.withCredentials = instanceSettings.withCredentials;
    this.url = instanceSettings.url;
    this.name = instanceSettings.name;
    this.index = instanceSettings.index;
    this.timeField = instanceSettings.jsonData.timeField;
    this.esVersion = instanceSettings.jsonData.esVersion;
    this.indexPattern = new IndexPattern(instanceSettings.index, instanceSettings.jsonData.interval);
    this.interval = instanceSettings.jsonData.timeInterval;
    this.queryBuilder = new ElasticQueryBuilder({
      timeField: this.timeField,
      esVersion: this.esVersion,
    });

    this._request = function(method, url, data) {
      var options = {
        url: this.url + "/" + url,
        method: method,
        data: data
      };

      if (this.basicAuth || this.withCredentials) {
        options.withCredentials = true;
      }
      if (this.basicAuth) {
        options.headers = {
          "Authorization": this.basicAuth
        };
      }

      return backendSrv.datasourceRequest(options);
    };

    this._get = function(url) {
      return this._request('GET', this.indexPattern.getIndexForToday() + url).then(function(results) {
        results.data.$$config = results.config;
        return results.data;
      });
    };

    this._post = function(url, data) {
      return this._request('POST', url, data).then(function(results) {
        results.data.$$config = results.config;
        return results.data;
      });
    };

    this.annotationQuery = function(options) {
      var annotation = options.annotation;
      var timeField = annotation.timeField || '@timestamp';
      var queryString = annotation.query || '*';
      var tagsField = annotation.tagsField || 'tags';
      var titleField = annotation.titleField || 'desc';
      var textField = annotation.textField || null;

      var range = {};
      range[timeField]= {
        from: options.range.from.valueOf(),
        to: options.range.to.valueOf(),
      };

      if (this.esVersion >= 2) {
        range[timeField]["format"] = "epoch_millis";
      }

      var queryInterpolated = templateSrv.replace(queryString, {}, 'lucene');
      var filter = { "bool": { "must": [{ "range": range }] } };
      var query = { "bool": { "should": [{ "query_string": { "query": queryInterpolated } }] } };
      var data = {
        "fields": [timeField, "_source"],
        "query" : { "filtered": { "query" : query, "filter": filter } },
        "size": 10000
      };

      var header = {search_type: "query_then_fetch", "ignore_unavailable": true};

      // old elastic annotations had index specified on them
      if (annotation.index) {
        header.index = annotation.index;
      } else {
        header.index = this.indexPattern.getIndexList(options.range.from, options.range.to);
      }

      var payload = angular.toJson(header) + '\n' + angular.toJson(data) + '\n';

      return this._post('_msearch', payload).then(function(res) {
        var list = [];
        var hits = res.responses[0].hits.hits;

        var getFieldFromSource = function(source, fieldName) {
          if (!fieldName) { return; }

          var fieldNames = fieldName.split('.');
          var fieldValue = source;

          for (var i = 0; i < fieldNames.length; i++) {
            fieldValue = fieldValue[fieldNames[i]];
            if (!fieldValue) {
              console.log('could not find field in annotation: ', fieldName);
              return '';
            }
          }

          if (_.isArray(fieldValue)) {
            fieldValue = fieldValue.join(', ');
          }
          return fieldValue;
        };

        for (var i = 0; i < hits.length; i++) {
          var source = hits[i]._source;
          var fields = hits[i].fields;
          var time = source[timeField];

          if (_.isString(fields[timeField]) || _.isNumber(fields[timeField])) {
            time = fields[timeField];
          }

          var event = {
            annotation: annotation,
            time: moment.utc(time).valueOf(),
            title: getFieldFromSource(source, titleField),
            tags: getFieldFromSource(source, tagsField),
            text: getFieldFromSource(source, textField)
          };

          list.push(event);
        }
        return list;
      });
    };

    this.testDatasource = function() {
      return this._get('/_stats').then(function() {
        return { status: "success", message: "Data source is working", title: "Success" };
      }, function(err) {
        if (err.data && err.data.error) {
          return { status: "error", message: angular.toJson(err.data.error), title: "Error" };
        } else {
          return { status: "error", message: err.status, title: "Error" };
        }
      });
    };

    this.getQueryHeader = function(searchType, timeFrom, timeTo) {
      var header = {search_type: searchType, "ignore_unavailable": true};
      header.index = this.indexPattern.getIndexList(timeFrom, timeTo);
      return angular.toJson(header);
    };

    this.query = function(options) {
      var payload = "";
      var target;
      var sentTargets = [];

      for (var i = 0; i < options.targets.length; i++) {
        target = options.targets[i];
        if (target.hide) {continue;}

        var queryObj = this.queryBuilder.build(target);
        var esQuery = angular.toJson(queryObj);
        var luceneQuery = target.query || '*';
        luceneQuery = templateSrv.replace(luceneQuery, options.scopedVars, 'lucene');
        luceneQuery = angular.toJson(luceneQuery);

        // remove inner quotes
        luceneQuery = luceneQuery.substr(1, luceneQuery.length - 2);
        esQuery = esQuery.replace("$lucene_query", luceneQuery);

        var searchType = queryObj.size === 0 ? 'count' : 'query_then_fetch';
        var header = this.getQueryHeader(searchType, options.range.from, options.range.to);
        payload +=  header + '\n';

        payload += esQuery + '\n';
        sentTargets.push(target);
      }

      if (sentTargets.length === 0) {
        return $q.when([]);
      }

      payload = payload.replace(/\$interval/g, options.interval);
      payload = payload.replace(/\$timeFrom/g, options.range.from.valueOf());
      payload = payload.replace(/\$timeTo/g, options.range.to.valueOf());
      payload = templateSrv.replace(payload, options.scopedVars);

      return this._post('_msearch', payload).then(function(res) {
        return new ElasticResponse(sentTargets, res).getTimeSeries();
      });
    };

    function escapeForJson(value) {
      return value.replace(/\"/g, '\\"');
    }

    function luceneThenJsonFormat(value) {
      return escapeForJson(templateSrv.luceneFormat(value));
    }

    this.getFields = function(query) {
      return this._get('/_mapping').then(function(res) {
        var fields = {};
        var typeMap = {
          'float': 'number',
          'double': 'number',
          'integer': 'number',
          'long': 'number',
          'date': 'date',
          'string': 'string',
        };

        for (var indexName in res) {
          var index = res[indexName];
          var mappings = index.mappings;
          if (!mappings) { continue; }
          for (var typeName in mappings) {
            var properties = mappings[typeName].properties;
            for (var field in properties) {
              var prop = properties[field];
              if (query.type && typeMap[prop.type] !== query.type) {
                continue;
              }
              if (prop.type && field[0] !== '_') {
                fields[field] = {text: field, type: prop.type};
              }
            }
          }
        }

        // transform to array
        return _.map(fields, function(value) {
          return value;
        });
      });
    };

    this.getTerms = function(queryDef) {
      var range = timeSrv.timeRange();
      var header = this.getQueryHeader('count', range.from, range.to);
      var esQuery = angular.toJson(this.queryBuilder.getTermsQuery(queryDef));

      esQuery = esQuery.replace("$lucene_query", escapeForJson(queryDef.query || '*'));
      esQuery = esQuery.replace(/\$timeFrom/g, range.from.valueOf());
      esQuery = esQuery.replace(/\$timeTo/g, range.to.valueOf());
      esQuery = header + '\n' + esQuery + '\n';

      return this._post('/_msearch?search_type=count', esQuery).then(function(res) {
        var buckets = res.responses[0].aggregations["1"].buckets;
        return _.map(buckets, function(bucket) {
          return {text: bucket.key, value: bucket.key};
        });
      });
    };

    this.metricFindQuery = function(query) {
      query = templateSrv.replace(query, {}, luceneThenJsonFormat);
      query = angular.fromJson(query);
      if (!query) {
        return $q.when([]);
      }

      if (query.find === 'fields') {
        return this.getFields(query);
      }
      if (query.find === 'terms') {
        return this.getTerms(query);
      }
    };

    this.getDashboard = function(id) {
      return this._get('/dashboard/' + id)
      .then(function(result) {
        return angular.fromJson(result._source.dashboard);
      });
    };

    this.searchDashboards = function() {
      var query = {
        query: { query_string: { query: '*' } },
        size: 10000,
        sort: ["_uid"],
      };

      return this._post(this.index + '/dashboard/_search', query)
      .then(function(results) {
        if(_.isUndefined(results.hits)) {
          return { dashboards: [], tags: [] };
        }

        var resultsHits = results.hits.hits;
        var displayHits = { dashboards: [] };

        for (var i = 0, len = resultsHits.length; i < len; i++) {
          var hit = resultsHits[i];
          displayHits.dashboards.push({
            id: hit._id,
            title: hit._source.title,
            tags: hit._source.tags
          });
        }

        return displayHits;
      });
    };
  }

  return {
    ElasticDatasource: ElasticDatasource
  };
});
<commit_msg>fix(elasticsearch): fixed templating lucene / json escaping issue, fixes #5228, fixes #5227<commit_after>define([
  'angular',
  'lodash',
  'moment',
  'app/core/utils/kbn',
  './query_builder',
  './index_pattern',
  './elastic_response',
  './query_ctrl',
],
function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticResponse) {
  'use strict';

  /** @ngInject */
  function ElasticDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv) {
    this.basicAuth = instanceSettings.basicAuth;
    this.withCredentials = instanceSettings.withCredentials;
    this.url = instanceSettings.url;
    this.name = instanceSettings.name;
    this.index = instanceSettings.index;
    this.timeField = instanceSettings.jsonData.timeField;
    this.esVersion = instanceSettings.jsonData.esVersion;
    this.indexPattern = new IndexPattern(instanceSettings.index, instanceSettings.jsonData.interval);
    this.interval = instanceSettings.jsonData.timeInterval;
    this.queryBuilder = new ElasticQueryBuilder({
      timeField: this.timeField,
      esVersion: this.esVersion,
    });

    this._request = function(method, url, data) {
      var options = {
        url: this.url + "/" + url,
        method: method,
        data: data
      };

      if (this.basicAuth || this.withCredentials) {
        options.withCredentials = true;
      }
      if (this.basicAuth) {
        options.headers = {
          "Authorization": this.basicAuth
        };
      }

      return backendSrv.datasourceRequest(options);
    };

    this._get = function(url) {
      return this._request('GET', this.indexPattern.getIndexForToday() + url).then(function(results) {
        results.data.$$config = results.config;
        return results.data;
      });
    };

    this._post = function(url, data) {
      return this._request('POST', url, data).then(function(results) {
        results.data.$$config = results.config;
        return results.data;
      });
    };

    this.annotationQuery = function(options) {
      var annotation = options.annotation;
      var timeField = annotation.timeField || '@timestamp';
      var queryString = annotation.query || '*';
      var tagsField = annotation.tagsField || 'tags';
      var titleField = annotation.titleField || 'desc';
      var textField = annotation.textField || null;

      var range = {};
      range[timeField]= {
        from: options.range.from.valueOf(),
        to: options.range.to.valueOf(),
      };

      if (this.esVersion >= 2) {
        range[timeField]["format"] = "epoch_millis";
      }

      var queryInterpolated = templateSrv.replace(queryString, {}, 'lucene');
      var filter = { "bool": { "must": [{ "range": range }] } };
      var query = { "bool": { "should": [{ "query_string": { "query": queryInterpolated } }] } };
      var data = {
        "fields": [timeField, "_source"],
        "query" : { "filtered": { "query" : query, "filter": filter } },
        "size": 10000
      };

      var header = {search_type: "query_then_fetch", "ignore_unavailable": true};

      // old elastic annotations had index specified on them
      if (annotation.index) {
        header.index = annotation.index;
      } else {
        header.index = this.indexPattern.getIndexList(options.range.from, options.range.to);
      }

      var payload = angular.toJson(header) + '\n' + angular.toJson(data) + '\n';

      return this._post('_msearch', payload).then(function(res) {
        var list = [];
        var hits = res.responses[0].hits.hits;

        var getFieldFromSource = function(source, fieldName) {
          if (!fieldName) { return; }

          var fieldNames = fieldName.split('.');
          var fieldValue = source;

          for (var i = 0; i < fieldNames.length; i++) {
            fieldValue = fieldValue[fieldNames[i]];
            if (!fieldValue) {
              console.log('could not find field in annotation: ', fieldName);
              return '';
            }
          }

          if (_.isArray(fieldValue)) {
            fieldValue = fieldValue.join(', ');
          }
          return fieldValue;
        };

        for (var i = 0; i < hits.length; i++) {
          var source = hits[i]._source;
          var fields = hits[i].fields;
          var time = source[timeField];

          if (_.isString(fields[timeField]) || _.isNumber(fields[timeField])) {
            time = fields[timeField];
          }

          var event = {
            annotation: annotation,
            time: moment.utc(time).valueOf(),
            title: getFieldFromSource(source, titleField),
            tags: getFieldFromSource(source, tagsField),
            text: getFieldFromSource(source, textField)
          };

          list.push(event);
        }
        return list;
      });
    };

    this.testDatasource = function() {
      return this._get('/_stats').then(function() {
        return { status: "success", message: "Data source is working", title: "Success" };
      }, function(err) {
        if (err.data && err.data.error) {
          return { status: "error", message: angular.toJson(err.data.error), title: "Error" };
        } else {
          return { status: "error", message: err.status, title: "Error" };
        }
      });
    };

    this.getQueryHeader = function(searchType, timeFrom, timeTo) {
      var header = {search_type: searchType, "ignore_unavailable": true};
      header.index = this.indexPattern.getIndexList(timeFrom, timeTo);
      return angular.toJson(header);
    };

    this.query = function(options) {
      var payload = "";
      var target;
      var sentTargets = [];

      for (var i = 0; i < options.targets.length; i++) {
        target = options.targets[i];
        if (target.hide) {continue;}

        var queryObj = this.queryBuilder.build(target);
        var esQuery = angular.toJson(queryObj);
        var luceneQuery = target.query || '*';
        luceneQuery = templateSrv.replace(luceneQuery, options.scopedVars, 'lucene');
        luceneQuery = angular.toJson(luceneQuery);

        // remove inner quotes
        luceneQuery = luceneQuery.substr(1, luceneQuery.length - 2);
        esQuery = esQuery.replace("$lucene_query", luceneQuery);

        var searchType = queryObj.size === 0 ? 'count' : 'query_then_fetch';
        var header = this.getQueryHeader(searchType, options.range.from, options.range.to);
        payload +=  header + '\n';

        payload += esQuery + '\n';
        sentTargets.push(target);
      }

      if (sentTargets.length === 0) {
        return $q.when([]);
      }

      payload = payload.replace(/\$interval/g, options.interval);
      payload = payload.replace(/\$timeFrom/g, options.range.from.valueOf());
      payload = payload.replace(/\$timeTo/g, options.range.to.valueOf());
      payload = templateSrv.replace(payload, options.scopedVars);

      return this._post('_msearch', payload).then(function(res) {
        return new ElasticResponse(sentTargets, res).getTimeSeries();
      });
    };

    function escapeForJson(value) {
      return value
        .replace(/\s/g, '\\ ')
        .replace(/\"/g, '\\"');
    }

    function luceneThenJsonFormat(value) {
      return escapeForJson(templateSrv.luceneFormat(value));
    }

    this.getFields = function(query) {
      return this._get('/_mapping').then(function(res) {
        var fields = {};
        var typeMap = {
          'float': 'number',
          'double': 'number',
          'integer': 'number',
          'long': 'number',
          'date': 'date',
          'string': 'string',
        };

        for (var indexName in res) {
          var index = res[indexName];
          var mappings = index.mappings;
          if (!mappings) { continue; }
          for (var typeName in mappings) {
            var properties = mappings[typeName].properties;
            for (var field in properties) {
              var prop = properties[field];
              if (query.type && typeMap[prop.type] !== query.type) {
                continue;
              }
              if (prop.type && field[0] !== '_') {
                fields[field] = {text: field, type: prop.type};
              }
            }
          }
        }

        // transform to array
        return _.map(fields, function(value) {
          return value;
        });
      });
    };

    this.getTerms = function(queryDef) {
      var range = timeSrv.timeRange();
      var header = this.getQueryHeader('count', range.from, range.to);
      var esQuery = angular.toJson(this.queryBuilder.getTermsQuery(queryDef));

      esQuery = esQuery.replace("$lucene_query", escapeForJson(queryDef.query || '*'));
      esQuery = esQuery.replace(/\$timeFrom/g, range.from.valueOf());
      esQuery = esQuery.replace(/\$timeTo/g, range.to.valueOf());
      esQuery = header + '\n' + esQuery + '\n';

      return this._post('/_msearch?search_type=count', esQuery).then(function(res) {
        var buckets = res.responses[0].aggregations["1"].buckets;
        return _.map(buckets, function(bucket) {
          return {text: bucket.key, value: bucket.key};
        });
      });
    };

    this.metricFindQuery = function(query) {
      query = templateSrv.replace(query, {}, luceneThenJsonFormat);
      query = angular.fromJson(query);
      if (!query) {
        return $q.when([]);
      }

      if (query.find === 'fields') {
        return this.getFields(query);
      }
      if (query.find === 'terms') {
        return this.getTerms(query);
      }
    };

    this.getDashboard = function(id) {
      return this._get('/dashboard/' + id)
      .then(function(result) {
        return angular.fromJson(result._source.dashboard);
      });
    };

    this.searchDashboards = function() {
      var query = {
        query: { query_string: { query: '*' } },
        size: 10000,
        sort: ["_uid"],
      };

      return this._post(this.index + '/dashboard/_search', query)
      .then(function(results) {
        if(_.isUndefined(results.hits)) {
          return { dashboards: [], tags: [] };
        }

        var resultsHits = results.hits.hits;
        var displayHits = { dashboards: [] };

        for (var i = 0, len = resultsHits.length; i < len; i++) {
          var hit = resultsHits[i];
          displayHits.dashboards.push({
            id: hit._id,
            title: hit._source.title,
            tags: hit._source.tags
          });
        }

        return displayHits;
      });
    };
  }

  return {
    ElasticDatasource: ElasticDatasource
  };
});
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      26.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('core/foundation/model.js');

/**
 * @class
 *
 * The root of all views.
 *
 */
M.View = M.Object.extend({

    /**
     * The type of this object.
     *
     * @property {String}
     */
    type: 'M.View',

    /**
     * A boolean value to definitely recognize a view as a view.
     *
     * @property {Boolean}
     */
    isView: YES,

    /**
     * Generic attribute for views. Some subclasses have a property that is more readable to its context than 'value'.
     * Internally these properties are mapped to 'value'.
     * e.g. in LabelView: value:this.text
     *
     * @property {Object, String}
     */
    value: null,

    /**
     * The path to a content that is bind to the view's value.
     *
     * @property {String, Object}
     */
    contentBinding: null,

    /**
     * An array specifying the view's children.
     *
     * @property {Object}
     */
    childViews: null,

    /**
     * Determines whether this view renders directly to the DOM or just returns its HTML representation.
     *
     * @property {Boolean}
     */
    renderToDOM: YES,

    /**
     * Indicates whether this view currently has the focus or not.
     *
     * @property {Boolean}
     */
    hasFocus: NO,

    /**
     * The id of the View used for the HTML attribute ID.
     */
    id: null,

    /**
     * Indicates whether the view should be displayed inline or not.
     */
    isInline: NO,

    /**
     * Indicates whether the view is visible or not.
     * Implemented via CSS's display property.
     */
    isVisible: YES,

    /*
     * Indicates whether the view is enabled or not.
     */
    isEnabled: YES,

    modelId: null,

    /**
     * This property can be used to assign a css class to the view using the jquery mobile
     * specific data-theme property. This allows you to create your custom styles.
     *
     * @property {String}
     */
    cssClass: null,

    /**
     * This property can be used to assign a css class to the view if an error occurs. The
     * applying of this class is automatically triggered if the validation of the view
     * goes wrong.
     *
     * @property {String}
     */
    cssClassOnError: null,

    /**
     * This property is used internally to recursively build the pages html representation.
     * It is once set within the render method and then eventually updated within the
     * renderUpdate method.
     *
     * @property {String} The pages html content.
     */
    html: '',

    /**
     * This method encapsulates the 'extend' method of M.Object for better reading of code syntax.
     * It triggers the content binding for this view,
     * gets an ID from and registers itself at the ViewManager.
     *
     * @param {Object} obj The mixed in object for the extend call.
     */
    design: function(obj) {
        var view = this.extend(obj);
        if(view.contentBinding) {
            view.attachToObservable(view.contentBinding);
        }
        view.id = M.Application.viewManager.getNextId();
        M.Application.viewManager.register(view);
        return view;
    },

     /**
     * Interface method.
     * Renders itself to HTML.
     * Render implementation is done by the special child obj of View (LabelView etc.).
     */
    render: function() {
        this.renderChildViews();
        return this.html;
    },

    /**
     * Interface method.
     * Updates itself in DOM.
     * Render implementation is done by the special child obj of View (LabelView etc.).
     */
    renderUpdate: function() {

    },

    /**
     * Triggers render() on all children.
     */
    renderChildViews: function() {
        if(this.childViews) {
            var childViews = $.trim(this.childViews).split(' ');
            for(var i in childViews) {
                if(this.type === 'M.PageView' && this[childViews[i]].type === 'M.TabBarView') {
                    this.hasTabBarView = YES;
                    this.tabBarView = this[childViews[i]];
                }
                this.html += this[childViews[i]].render();
            }
        }
    },

    /**
     * Clears the html property of a view and triggers the same method on all of its
     * child views.
     */
    clearHtml: function() {
        this.html = '';
        if(this.childViews) {
            var childViews = $.trim(this.childViews).split(' ');
            for(var i in childViews) {
                this[childViews[i]].clearHtml();
            }
        }
    },

    /**
     * If the view's computedValue property is set, compute the value. This allows you to
     * apply a method to a dynamically set value. E.g. you can provide your value with an
     * toUpperCase().
     */
    computeValue: function() {
        if(this.computedValue) {
            this.value = this.computedValue.operation(this.computedValue.valuePattern ? this.value : this.computedValue.value, this);
        }
    },

    /**
     * Interface method.
     * Triggers rendering engine to style this view/apply a theme.
     */
    theme: function() {
        this.themeChildViews();
    },

    /**
     * Triggers theme() on all children.
     */
    themeChildViews: function() {
        if(this.childViews) {
            var childViews = $.trim(this.childViews).split(' ');
            for(var i in childViews) {
                this[childViews[i]].theme();
            }
        }
    },

    /**
     * contentDidChange is called by the observable when observable's state did change.
     * It updates the view's value property.
     */
    contentDidChange: function(){
        var bindingPath = this.contentBinding.split('.');
        if(bindingPath && bindingPath.length === 3 && !(this.hasFocus && this.type === 'M.TextFieldView')) {
            this.value = eval(bindingPath[0])[bindingPath[1]][bindingPath[2]];
            this.renderUpdate();
            this.delegateValueUpdate();
        } else if(bindingPath && bindingPath.length === 3) {
            return;
        } else {
            M.Logger.log('bindingPath not valid', M.WARN);
        }
    },

    /**
     * This method attaches itself to an observable.
     *
     * @param {String} contentBinding The path to the observable property.
     */
    attachToObservable: function(contentBinding) {
        var bindingPath = contentBinding.split('.');
        if(bindingPath && bindingPath.length === 3 && eval(bindingPath[0]) && eval(bindingPath[0])[bindingPath[1]]) {
            eval(bindingPath[0])[bindingPath[1]].observable.attach(this, bindingPath[2]);
            this.isObserver = YES;
        } else {
            M.Logger.log('bindingPath not valid', M.WARN);
        }
    },

    /**
     * Interface method.
     * This method sets its value to the value it has in its DOM representation.
     */
    setValueFromDOM: function() {

    },

    /**
     * This method delegates any value changes to a controller, if the 'contentBindingReverse'
     * property is specified.
     */
    delegateValueUpdate: function() {
        /* delegate value updates to a binded controller,
           but only if the view currently is the master */
        if(this.contentBindingReverse && this.hasFocus) {
            var params = this.contentBindingReverse.split('.');
            var controller = eval(params[0]);
            controller[params[1]].set(params[2], this.value);
        }
    },

    /**
     * Interface method.
     * Method to append css styles and other style specific inline attributes to the rendered view.
     */
    style: function() {

    },

    /**
     * This method is called whenever the view gets the focus.
     */
    gotFocus: function() {
        this.hasFocus = YES;
    },

    /**
     * This method is called whenever the view lost the focus.
     */
    lostFocus: function() {
        this.hasFocus = NO;
    },

    /**
     * Secure the passed string.
     *
     * This is mainly used for securing input elements like text fields but since it is
     * part of M.View it can be used and called out of any view.
     *
     * So far we only replace '<' and '>' with their corresponding html entity. The functionality
     * of this method will be extended in the future.
     *
     * @param {String} str The string to be escaped
     */
    secure: function(str) {
        return str.replace(/</g, "<").replace(/>/g, ">");
    },

    nl2br: function(str) {
        if(str) {
            if(typeof(str) !== 'string') {
                str = String(str);
            }
            return str.replace(/\n/g, '
\n');
        }
        return str;
    },

    /**
     * This method writes the view's html string into the DOM.
     */
    writeToDOM: function() {
        document.write(this.html);
    },

    /**
     * Adds a css class to the view's DOM representation.
     *
     * @property {String} cssClass The css class to be added.
     */
    addClass: function(cssClass) {
        $('#' + this.id).addClass(cssClass);
    },

    /**
     * Removes a css class to the view's DOM representation.
     *
     * @property {String} cssClass The css class to be removed.
     */
    removeClass: function(cssClass) {
        $('#' + this.id).removeClass(cssClass);
    }

});<commit_msg>Added cssClassOnInit property<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      26.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('core/foundation/model.js');

/**
 * @class
 *
 * The root of all views.
 *
 */
M.View = M.Object.extend({

    /**
     * The type of this object.
     *
     * @property {String}
     */
    type: 'M.View',

    /**
     * A boolean value to definitely recognize a view as a view.
     *
     * @property {Boolean}
     */
    isView: YES,

    /**
     * Generic attribute for views. Some subclasses have a property that is more readable to its context than 'value'.
     * Internally these properties are mapped to 'value'.
     * e.g. in LabelView: value:this.text
     *
     * @property {Object, String}
     */
    value: null,

    /**
     * The path to a content that is bind to the view's value.
     *
     * @property {String, Object}
     */
    contentBinding: null,

    /**
     * An array specifying the view's children.
     *
     * @property {Object}
     */
    childViews: null,

    /**
     * Determines whether this view renders directly to the DOM or just returns its HTML representation.
     *
     * @property {Boolean}
     */
    renderToDOM: YES,

    /**
     * Indicates whether this view currently has the focus or not.
     *
     * @property {Boolean}
     */
    hasFocus: NO,

    /**
     * The id of the View used for the HTML attribute ID.
     */
    id: null,

    /**
     * Indicates whether the view should be displayed inline or not.
     */
    isInline: NO,

    /**
     * Indicates whether the view is visible or not.
     * Implemented via CSS's display property.
     */
    isVisible: YES,

    /*
     * Indicates whether the view is enabled or not.
     */
    isEnabled: YES,

    modelId: null,

    /**
     * This property can be used to assign a css class to the view using the jquery mobile
     * specific data-theme property. This allows you to create your custom styles.
     *
     * @property {String}
     */
    cssClass: null,

    /**
     * This property can be used to assign a css class to the view if an error occurs. The
     * applying of this class is automatically triggered if the validation of the view
     * goes wrong.
     *
     * @property {String}
     */
    cssClassOnError: null,

    /**
     * This property can be used to assign a css class to the view on its initialization. This
     * property is mainly used for input ui elements like text fields, that might have a initial
     * value that should be rendered in a different style than the later value entered by the
     * user.
     *
     * @property {String}
     */
    cssClassOnInit: null,

    /**
     * This property is used internally to recursively build the pages html representation.
     * It is once set within the render method and then eventually updated within the
     * renderUpdate method.
     *
     * @property {String} The pages html content.
     */
    html: '',

    /**
     * This method encapsulates the 'extend' method of M.Object for better reading of code syntax.
     * It triggers the content binding for this view,
     * gets an ID from and registers itself at the ViewManager.
     *
     * @param {Object} obj The mixed in object for the extend call.
     */
    design: function(obj) {
        var view = this.extend(obj);
        if(view.contentBinding) {
            view.attachToObservable(view.contentBinding);
        }
        view.id = M.Application.viewManager.getNextId();
        M.Application.viewManager.register(view);
        return view;
    },

     /**
     * Interface method.
     * Renders itself to HTML.
     * Render implementation is done by the special child obj of View (LabelView etc.).
     */
    render: function() {
        this.renderChildViews();
        return this.html;
    },

    /**
     * Interface method.
     * Updates itself in DOM.
     * Render implementation is done by the special child obj of View (LabelView etc.).
     */
    renderUpdate: function() {

    },

    /**
     * Triggers render() on all children.
     */
    renderChildViews: function() {
        if(this.childViews) {
            var childViews = $.trim(this.childViews).split(' ');
            for(var i in childViews) {
                if(this.type === 'M.PageView' && this[childViews[i]].type === 'M.TabBarView') {
                    this.hasTabBarView = YES;
                    this.tabBarView = this[childViews[i]];
                }
                this.html += this[childViews[i]].render();
            }
        }
    },

    /**
     * Clears the html property of a view and triggers the same method on all of its
     * child views.
     */
    clearHtml: function() {
        this.html = '';
        if(this.childViews) {
            var childViews = $.trim(this.childViews).split(' ');
            for(var i in childViews) {
                this[childViews[i]].clearHtml();
            }
        }
    },

    /**
     * If the view's computedValue property is set, compute the value. This allows you to
     * apply a method to a dynamically set value. E.g. you can provide your value with an
     * toUpperCase().
     */
    computeValue: function() {
        if(this.computedValue) {
            this.value = this.computedValue.operation(this.computedValue.valuePattern ? this.value : this.computedValue.value, this);
        }
    },

    /**
     * Interface method.
     * Triggers rendering engine to style this view/apply a theme.
     */
    theme: function() {
        this.themeChildViews();
    },

    /**
     * Triggers theme() on all children.
     */
    themeChildViews: function() {
        if(this.childViews) {
            var childViews = $.trim(this.childViews).split(' ');
            for(var i in childViews) {
                this[childViews[i]].theme();
            }
        }
    },

    /**
     * contentDidChange is called by the observable when observable's state did change.
     * It updates the view's value property.
     */
    contentDidChange: function(){
        var bindingPath = this.contentBinding.split('.');
        if(bindingPath && bindingPath.length === 3 && !(this.hasFocus && this.type === 'M.TextFieldView')) {
            this.value = eval(bindingPath[0])[bindingPath[1]][bindingPath[2]];
            this.renderUpdate();
            this.delegateValueUpdate();
        } else if(bindingPath && bindingPath.length === 3) {
            return;
        } else {
            M.Logger.log('bindingPath not valid', M.WARN);
        }
    },

    /**
     * This method attaches itself to an observable.
     *
     * @param {String} contentBinding The path to the observable property.
     */
    attachToObservable: function(contentBinding) {
        var bindingPath = contentBinding.split('.');
        if(bindingPath && bindingPath.length === 3 && eval(bindingPath[0]) && eval(bindingPath[0])[bindingPath[1]]) {
            eval(bindingPath[0])[bindingPath[1]].observable.attach(this, bindingPath[2]);
            this.isObserver = YES;
        } else {
            M.Logger.log('bindingPath not valid', M.WARN);
        }
    },

    /**
     * Interface method.
     * This method sets its value to the value it has in its DOM representation.
     */
    setValueFromDOM: function() {

    },

    /**
     * This method delegates any value changes to a controller, if the 'contentBindingReverse'
     * property is specified.
     */
    delegateValueUpdate: function() {
        /* delegate value updates to a binded controller,
           but only if the view currently is the master */
        if(this.contentBindingReverse && this.hasFocus) {
            var params = this.contentBindingReverse.split('.');
            var controller = eval(params[0]);
            controller[params[1]].set(params[2], this.value);
        }
    },

    /**
     * Interface method.
     * Method to append css styles and other style specific inline attributes to the rendered view.
     */
    style: function() {

    },

    /**
     * This method is called whenever the view gets the focus.
     */
    gotFocus: function() {
        this.hasFocus = YES;
    },

    /**
     * This method is called whenever the view lost the focus.
     */
    lostFocus: function() {
        this.hasFocus = NO;
    },

    /**
     * Secure the passed string.
     *
     * This is mainly used for securing input elements like text fields but since it is
     * part of M.View it can be used and called out of any view.
     *
     * So far we only replace '<' and '>' with their corresponding html entity. The functionality
     * of this method will be extended in the future.
     *
     * @param {String} str The string to be escaped
     */
    secure: function(str) {
        return str.replace(/</g, "<").replace(/>/g, ">");
    },

    nl2br: function(str) {
        if(str) {
            if(typeof(str) !== 'string') {
                str = String(str);
            }
            return str.replace(/\n/g, '
\n');
        }
        return str;
    },

    /**
     * This method writes the view's html string into the DOM.
     */
    writeToDOM: function() {
        document.write(this.html);
    },

    /**
     * Adds a css class to the view's DOM representation.
     *
     * @property {String} cssClass The css class to be added.
     */
    addClass: function(cssClass) {
        $('#' + this.id).addClass(cssClass);
    },

    /**
     * Removes a css class to the view's DOM representation.
     *
     * @property {String} cssClass The css class to be removed.
     */
    removeClass: function(cssClass) {
        $('#' + this.id).removeClass(cssClass);
    }

});<|endoftext|>


<commit_before>/**
 * Chris Troutner
 * https://github.com/skagitpublishing/connextCMS
 */

/**
 * Example plugin that adds a toolbar button and menu item.
 */
tinymce.PluginManager.add('image_gallery', function(editor, url) {
	// Add a button that opens a window
	editor.addButton('image_gallery', {
		icon: 'image',
    tooltip: 'Insert/edit image',
		onclick: function() {
			//debugger;

      // Open window
			editor.windowManager.open({
        title: 'Image Library',
				url: url + '/dialog.html',
				width: 800,
				height: 400,
        buttons: [
					{
						text: 'Insert',
            onclick: function() {
              //debugger;

              //Wrap the insertion of an image in an 'undo' function.
              editor.undoManager.transact(function() {
                //debugger;

                try {

                  top.log.push('Insert button pressed in image_gallery plug of TinyMCE.');

                  //Retrieve a handle for the dialog window.
                  var win = editor.windowManager.getWindows()[0];

                  //If no image was selected, then exit.
                  if( top.global.tinymce.selectedImage == null ) {
                    win.close();
                    return;
                  }

                  //Retrieve the values of the input fields.
                  var imageSize = win.getContentWindow().document.getElementById('imageSize').value;
                  var altTag = win.getContentWindow().document.getElementById('altTag').value;
                  var caption = win.getContentWindow().document.getElementById('caption').value;
                  var imgAlign = win.getContentWindow().document.getElementById('imageAlign').value;

                  //Retrive the parent and child image models for the selected image.
                  var thisImage = top.global.thumbnailImageCollection.models[top.global.tinymce.selectedImage];

                  var parentImageGUID = thisImage.get('parent');
                  if(parentImageGUID == "")
                    var parentImage = thisImage;
                  else
                    var parentImage = top.global.imageUploadCollection.get(parentImageGUID);

                  var childrenGUIDs = parentImage.get('children').split(',');

                  var imageModel;
                  var divWidth;
                  if( imageSize == "300px" ) {
                    imageModel = top.global.imageUploadCollection.get(childrenGUIDs[0]);
                    divWidth = "300px";
                  }
                  else if( imageSize == "600px" ) {
                    imageModel = top.global.imageUploadCollection.get(childrenGUIDs[1]);
                    divWidth = "600px";
                  }
                  else if( imageSize == "1200px" ) {
                    imageModel = top.global.imageUploadCollection.get(childrenGUIDs[2]);
                    divWidth = "1200px";
                  }
                  else {
                    //debugger;
                    imageModel = parentImage;
                    divWidth = parentImage.get('width')+"px";
                  }
                  //var imageURL = 'http://'+top.global.serverIp+':'+top.global.serverPort+imageModel.attributes.image.path.slice(6)+'/'+imageModel.attributes.image.filename;
                  var imageURL = imageModel.attributes.url;

                  var preHTML = "";
                  var postHTML = "";

                  //Handle Alignment
                  if( imgAlign == "center" ) {
                    preHTML = "
";
                    postHTML = "
";
                  } else if( imgAlign == "right") {
                    preHTML = "
";
                    postHTML = "
";
                  } else if( imgAlign == "left") {
                    preHTML = "
";
                    postHTML = "
";
                  }

                  //Handle a caption
                  if( caption != "" ) {
                    preHTML = preHTML+'
';
                    postHTML = '
'+caption+'

'+postHTML;
                  }

                  tinymce.activeEditor.selection.setContent(preHTML+''+postHTML);

                  // Close the window
                  win.close();

                } catch(err) {
                  console.error('Error while trying to insert image in image_gallery plugin for TinyMCE. Error message: ');
                  console.error(err.message);

                  log.push('Error while trying to insert image in image_gallery plugin for TinyMCE. Error message: ');
                  log.push(err.message);
                  sendLog();
                }
              });

						}

					},

					{text: 'Close', onclick: 'close'}
				],

			});

		}
	});

});<commit_msg>Fixing formatting in TinyMCE image gallery plugin<commit_after>/**
 * Chris Troutner
 * https://github.com/skagitpublishing/connextCMS
 */

/**
 * Example plugin that adds a toolbar button and menu item.
 */
tinymce.PluginManager.add('image_gallery', function(editor, url) {
	// Add a button that opens a window
	editor.addButton('image_gallery', {
		icon: 'image',
    tooltip: 'Insert/edit image',
		onclick: function() {
			//debugger;

      // Open window
			editor.windowManager.open({
        title: 'Image Library',
				url: url + '/dialog.html',
				width: 800,
				height: 400,
        buttons: [
					{
						text: 'Insert',
            onclick: function() {
              //debugger;

              //Wrap the insertion of an image in an 'undo' function.
              editor.undoManager.transact(function() {
                //debugger;

                try {

                  top.log.push('Insert button pressed in image_gallery plug of TinyMCE.');

                  //Retrieve a handle for the dialog window.
                  var win = editor.windowManager.getWindows()[0];

                  //If no image was selected, then exit.
                  if( top.global.tinymce.selectedImage == null ) {
                    win.close();
                    return;
                  }

                  //Retrieve the values of the input fields.
                  var imageSize = win.getContentWindow().document.getElementById('imageSize').value;
                  var altTag = win.getContentWindow().document.getElementById('altTag').value;
                  var caption = win.getContentWindow().document.getElementById('caption').value;
                  var imgAlign = win.getContentWindow().document.getElementById('imageAlign').value;

                  //Retrive the parent and child image models for the selected image.
                  var thisImage = top.global.thumbnailImageCollection.models[top.global.tinymce.selectedImage];

                  var parentImageGUID = thisImage.get('parent');
                  if(parentImageGUID == "")
                    var parentImage = thisImage;
                  else
                    var parentImage = top.global.imageUploadCollection.get(parentImageGUID);

                  var childrenGUIDs = parentImage.get('children').split(',');

                  var imageModel;
                  var divWidth;
                  if( imageSize == "300px" ) {
                    imageModel = top.global.imageUploadCollection.get(childrenGUIDs[0]);
                    divWidth = "300px";
                  }
                  else if( imageSize == "600px" ) {
                    imageModel = top.global.imageUploadCollection.get(childrenGUIDs[1]);
                    divWidth = "600px";
                  }
                  else if( imageSize == "1200px" ) {
                    imageModel = top.global.imageUploadCollection.get(childrenGUIDs[2]);
                    divWidth = "1200px";
                  }
                  else {
                    //debugger;
                    imageModel = parentImage;
                    divWidth = parentImage.get('width')+"px";
                  }
                  //var imageURL = 'http://'+top.global.serverIp+':'+top.global.serverPort+imageModel.attributes.image.path.slice(6)+'/'+imageModel.attributes.image.filename;
                  var imageURL = imageModel.attributes.url;

                  var preHTML = "";
                  var postHTML = "";

                  //Handle Alignment
                  if( imgAlign == "center" ) {
                    preHTML = "
";
                    postHTML = "
";
                  } else if( imgAlign == "right") {
                    preHTML = "
";
                    postHTML = "
";
                  } else if( imgAlign == "left") {
                    preHTML = "
";
                    postHTML = "
";
                  }

                  //Handle a caption
                  if( caption != "" ) {
                    preHTML = preHTML+'
';
                    postHTML = '
'+caption+'

'+postHTML;
                  }

                  tinymce.activeEditor.selection.setContent(preHTML+''+postHTML);

                  // Close the window
                  win.close();

                } catch(err) {
                  console.error('Error while trying to insert image in image_gallery plugin for TinyMCE. Error message: ');
                  console.error(err.message);

                  log.push('Error while trying to insert image in image_gallery plugin for TinyMCE. Error message: ');
                  log.push(err.message);
                  sendLog();
                }
              });

						}

					},

					{text: 'Close', onclick: 'close'}
				],

			});

		}
	});

});<|endoftext|>


<commit_before>'use strict';

angular.module('core').controller('HomeController', ['$scope', '$location','Authentication',
  function($scope, $location, Authentication) {
  // This provides Authentication context.
  if (Authentication.user) {
    $location.path('/vocablists');
  }
  $scope.authentication = Authentication;
  }
]);
<commit_msg>Fixes tabbing<commit_after>'use strict';

angular.module('core').controller('HomeController', ['$scope', '$location','Authentication',
  function($scope, $location, Authentication) {
    // This provides Authentication context.
    if (Authentication.user) {
      $location.path('/vocablists');
    }
    $scope.authentication = Authentication;
  }
]);
<|endoftext|>


<commit_before>'use strict';

angular.module('core').controller('itemController', ['$scope', '$window' ,'Authentication', 'itemService',
	function($scope, $window, Authentication, itemService) {
		// This provides Authentication context.
		$scope.authentication = Authentication;

	// Some example string - remove in prod
        $scope.helloText = 'Item Test';
        $scope.testuser = $scope.authentication.user.displayName;

    	$scope.items = itemService.query();
		$scope.newItem = {};

	$scope.post = function() {
	  itemService.save({

		  item.created_by: $scope.authentication.user._id
		, item.created_by_name: $scope.authentication.user.displayName
		, item.created_at: $scope.newItem.created_at
		, item.UPC: $scope.newItem.UPC
		, item.Description: $scope.newItem.Description
		, item.Product_Group: $scope.newItem.Product_Group
		, item.Unit_Size: $scope.newItem.Unit_Size
		, item.Unit_Measure: $scope.newItem.Unit_Measure
		, item.Case_Units: $scope.newItem.Case_Units
		, item.Unit_Price_FOB: $scope.newItem.Unit_Price_FOB
		, item.Unit_Price_Delivered: $scope.newItem.Unit_Price_Delivered
		, item.Suggested_Retail_Price: $scope.newItem.Suggested_Retail_Price
		, item.Margin_FOB: $scope.newItem.Margin_FOB
		, item.Margin_Delivered: $scope.newItem.Margin_Delivered
		, item.Shelf_Life_DOM_Days: $scope.newItem.Shelf_Life_DOM_Days
		, item.Shelf_Life_First_REC_Days: $scope.newItem.Shelf_Life_First_REC_Days
		, item.Internal_Reference_Code: $scope.newItem.Internal_Reference_Code
		, item.Internal_Item_Number: $scope.newItem.Internal_Item_Number
		, item.FOB_Case_Price: $scope.newItem.FOB_Case_Price
		, item.Delivered_Case_Price: $scope.newItem.Delivered_Case_Price
		, item.Pallet_Ti_Hi: $scope.newItem.Pallet_Ti_Hi
		, item.Case_Net_Wt_LBS: $scope.newItem.Case_Net_Wt_LBS
		, item.Case_UCC: $scope.newItem.Case_UCC

	  }, function(){
	    $scope.items = itemService.query();
	    $scope.newItem = {};
	    $window.location.href = '/#!/item-form';
	  });
	};

	$scope.delete = function(item)	{
		itemService.delete({id: item._id});
		$scope.item = itemService.query();
	};

	}
]);
<commit_msg>Update item.client.controller.js<commit_after>'use strict';

angular.module('core').controller('itemController', ['$scope', '$window' ,'Authentication', 'itemService',
	function($scope, $window, Authentication, itemService) {
		// This provides Authentication context.
		$scope.authentication = Authentication;

	// Some example string - remove in prod
        $scope.helloText = 'Item Test';
        $scope.testuser = $scope.authentication.user.displayName;

    	$scope.items = itemService.query();
		$scope.newItem = {};

	$scope.post = function() {
	  itemService.save({

		  created_by: $scope.authentication.user._id
		, created_by_name: $scope.authentication.user.displayName
		, created_at: $scope.newItem.created_at
		, UPC: $scope.newItem.UPC
		, Description: $scope.newItem.Description
		, Product_Group: $scope.newItem.Product_Group
		, Unit_Size: $scope.newItem.Unit_Size
		, Unit_Measure: $scope.newItem.Unit_Measure
		, Case_Units: $scope.newItem.Case_Units
		, Unit_Price_FOB: $scope.newItem.Unit_Price_FOB
		, Unit_Price_Delivered: $scope.newItem.Unit_Price_Delivered
		, Suggested_Retail_Price: $scope.newItem.Suggested_Retail_Price
		, Margin_FOB: $scope.newItem.Margin_FOB
		, Margin_Delivered: $scope.newItem.Margin_Delivered
		, Shelf_Life_DOM_Days: $scope.newItem.Shelf_Life_DOM_Days
		, Shelf_Life_First_REC_Days: $scope.newItem.Shelf_Life_First_REC_Days
		, Internal_Reference_Code: $scope.newItem.Internal_Reference_Code
		, Internal_Item_Number: $scope.newItem.Internal_Item_Number
		, FOB_Case_Price: $scope.newItem.FOB_Case_Price
		, Delivered_Case_Price: $scope.newItem.Delivered_Case_Price
		, Pallet_Ti_Hi: $scope.newItem.Pallet_Ti_Hi
		, Case_Net_Wt_LBS: $scope.newItem.Case_Net_Wt_LBS
		, Case_UCC: $scope.newItem.Case_UCC

	  }, function(){
	    $scope.items = itemService.query();
	    $scope.newItem = {};
	    $window.location.href = '/#!/item-form';
	  });
	};

	$scope.delete = function(item)	{
		itemService.delete({id: item._id});
		$scope.item = itemService.query();
	};

	}
]);
<|endoftext|>


<commit_before>var _ = require("underscore");
var mockEvents = require("./MockEvents");
var Event = require('../../models/Event');

// TODO: Replace mock events by MongoDB.
// TODO: Order by 'startDate asc' to show most recent events.

module.exports.dbPreload = function() {
  console.log("Preloading database...");
  Event.find({}, function(err, events) {
    if (events.length > 0) return;

    _.map(mockEvents, function(ev) {
      var newEvent = new Event(ev)
      newEvent.save(function(err) {
        if (err != null) console.error("cound not save mocked Events: " + err)
      })
    });
  })
};

module.exports.findAll = function() {
  return mockEvents;
};

module.exports.findByActivity = function(act) {
  return _.filter(mockEvents, function(e) { return e.activity === act; });
};

module.exports.findById = function(id) {
  return _.findWhere(mockEvents, {id: id});
};<commit_msg>fixed merging issues<commit_after>var _ = require("underscore");
var mockEvents = require("./MockEvents");
var Event = require('../../models/Event');

// TODO: Replace mock events by MongoDB.
// TODO: Order by 'startDate asc' to show most recent events.

module.exports.dbPreload = function() {
  console.log("Preloading database...");
  Event.find({}, function(err, events) {
    if (events.length > 0) return;

    _.map(mockEvents, function(ev) {
      var newEvent = new Event(ev)
      newEvent.save(function(err) {
        if (err != null) console.error("cound not save mocked Events: " + err)
      })
    });
  })
};

module.exports.findByAuthor = function () {
  // TODO
};

module.exports.findAll = function (cb) {
  return Event.find({}, function (err, events) {
    cb(err, events);
  });
};

module.exports.findByActivity = function(act) {
  return _.filter(mockEvents, function(e) { return e.activity === act; });
};

module.exports.findById = function(id) {
  return _.findWhere(mockEvents, {id: id});
};<|endoftext|>


<commit_before>// load model to save searches
var searchModel = require('../models/searchModel.js');

// twitter api node module
var Twit = require('twit');

// load required api keys/secrets
var conf = require('../conf.js');

// create and save geo search then perform cb
var createAndSaveGeoSearch = function(theGeoSearch, cb) {
  var newGeoSearch = new searchModel.GeoSearch;
  // newGeoSearch.location = theGeoSearch.location;
  // newGeoSearch.latitude = theGeoSearch.latitude;
  for (var key in theGeoSearch){
    newGeoSearch[key] = theGeoSearch[key];
  };
  console.log('about to save-', newGeoSearch);
  newGeoSearch.save(function(err, savedSearch) {
    console.log('new GeoSearch saved-', savedSearch);
    cb(err, savedSearch)
  })
};

// find saved search then perform cb
var findGeoSearch = function(searchId, cb) {
  console.log('finding search id-', searchId);

  searchModel.GeoSearch.findById(searchId, function(err, foundSearch) {
    if (err){
      console.log('error happened-', err);
    }
    console.log('found this search-', foundSearch);
    cb(foundSearch)
  })
}

// perform the twitter api search
var twitterSearch = function(query, cb, options) {

  var T = new Twit({
    consumer_key:         conf.twitterApiKey
  , consumer_secret:      conf.twitterApiSecret
  , access_token:         conf.myTwitterToken
  , access_token_secret:  conf.myTwitterTokenSecret
  });

  var count = options.count || 20;
  var geocode = options.geocode || '';
  var until = options.until || '';
  var since_id = options.since_id || '';

  T.get('search/tweets', {
    q: query,
    geocode: geocode,
    count: count,
    until: until,
    since_id: since_id
  }, function(err, data, response) {
    console.log('tweets returned-', data);
    cb(data);
  })

}

// setup searchController object to be exported
var searchController = {
  postSearch: function(req, res) {
    // check if first if user is authenticated

    // save the search and return id
    var theGeoSearch = req.body;
    console.log('attempting to begin save search-', theGeoSearch);
    createAndSaveGeoSearch(theGeoSearch, function(err, savedSearch) {
      if (err){
        console.log('error saving');
        res.send(500, 'error saving saving/permforming search');
        return;
      }
      console.log('sending back after save-', savedSearch)
      res.send(savedSearch);
    })
  },
  // perform twitter api search route
  getSearch: function(req, res) {
    console.log('req-', req);
    console.log('req.query-', req.query);
    var searchId = req.query.searchId;

    findGeoSearch(searchId, function(foundSearch) {
      console.log('sending found search-', foundSearch);
      res.send(foundSearch)
    })
  }
}

module.exports = searchController;<commit_msg>add twitter api search by geo and return tweets<commit_after>// load model to save searches
var searchModel = require('../models/searchModel.js');

// twitter api node module
var Twit = require('twit');

// load required api keys/secrets
var conf = require('../conf.js');

// create and save geo search then perform cb
var createAndSaveGeoSearch = function(theGeoSearch, cb) {
  var newGeoSearch = new searchModel.GeoSearch;
  // newGeoSearch.location = theGeoSearch.location;
  // newGeoSearch.latitude = theGeoSearch.latitude;
  for (var key in theGeoSearch){
    newGeoSearch[key] = theGeoSearch[key];
  };
  console.log('about to save-', newGeoSearch);
  newGeoSearch.save(function(err, savedSearch) {
    console.log('new GeoSearch saved-', savedSearch);
    cb(err, savedSearch)
  })
};

// find saved search then perform cb
var findGeoSearch = function(searchId, cb) {
  console.log('finding search id-', searchId);

  searchModel.GeoSearch.findById(searchId, function(err, foundSearch) {
    if (err){
      console.log('error happened-', err);
    }
    console.log('found this search-', foundSearch);
    cb(foundSearch)
  })
}

// perform the twitter api search
var twitterSearch = function(cb, options) {

  var T = new Twit({
    consumer_key:         conf.twitterApiKey
  , consumer_secret:      conf.twitterApiSecret
  , access_token:         conf.myTwitterToken
  , access_token_secret:  conf.myTwitterTokenSecret
  });

  var query = options.query || '';
  var count = options.count || 20;
  var geocode = options.geocode || '';
  var until = options.until || '';
  var since_id = options.since_id || '';

  console.log('about to perform twitter api call-', query, geocode, count);

  T.get('search/tweets', {
    q: query,
    geocode: geocode,
    count: count
  }, function(err, data, response) {
    if (err){
      console.log('err-', err);
    }
    console.log('response-', response);
    console.log('tweets returned-', data);
    cb(data);
  })

}

// setup searchController object to be exported
var searchController = {
  postSearch: function(req, res) {
    // check if first if user is authenticated

    // save the search and return id
    var theGeoSearch = req.body;
    console.log('attempting to begin save search-', theGeoSearch);
    createAndSaveGeoSearch(theGeoSearch, function(err, savedSearch) {
      if (err){
        console.log('error saving');
        res.send(500, 'error saving saving/permforming search');
        return;
      }
      console.log('sending back after save-', savedSearch)
      res.send(savedSearch);
    })
  },
  // perform twitter api search route
  getSearch: function(req, res) {
    var searchId = req.query.searchId;
    console.log('req query searchId-', searchId);
    findGeoSearch(searchId, function(foundSearch) {
      // setup twitter api search params
      var options = {
        query: foundSearch.query,
        geocode: ''+foundSearch.latitude+','+foundSearch.longitude+','+foundSearch.radius+foundSearch.radiusUnit.toLowerCase()
      }
      console.log('submitting twitter api call with these options-', options);
      twitterSearch(function(tweets) {
        res.send(tweets)
      }, options);
    });
  }
}

module.exports = searchController;<|endoftext|>


<commit_before>'use strict';
var constant = require('../mixin/constant');
var Video = require('../models/video');

function VideoController() {

}

VideoController.prototype.getVideo = (req, res, next) => {
  console.log(req.params.videoId);
  console.log('11111111');

  //console.log(' find movie');
  ////查找电影
  //Video.find({category: '电影'}, ('screenshotsPath title description label'), (err, doc)=> {
  //  if (err) return next(err);
  //  console.log(doc);
  //  res.send(doc);
  //})
};

module.exports = VideoController;
<commit_msg>add getVedio method<commit_after>'use strict';
var constant = require('../mixin/constant');
var Video = require('../models/video');

function VideoController() {

}

VideoController.prototype.getVideo = (req, res, next) => {
  var videoId = req.params.videoId;

  //根据videoId 去查找 视频资源
  Video.findById(videoId, ('mimetype path'), (err, doc)=> {
    if (err) return next(err);
    res.send(doc);
  });
};

module.exports = VideoController;
<|endoftext|>