<commit_before>$(function() {
    var pageCache = {};

    // bindWindowScrollHandler();
    bindChangePage();
    prefetchPage();
    bindKeyboardMove();

    function prefetchPage() {
        // load pages
        $(".archives.page-nav .page").each(function(idx, ele) {
            var $ele = $(ele);
            var page = $ele.html();
            var url = $ele.attr("href");

            if (!pageCache.hasOwnProperty(page)) {
                $.get(url, function(data) {})
                    .done(function(data) {
                        pageCache[page] = data;
                    });
            }
        });
    }

    function bindChangePage() {
        function updateContainerByPage(page) {
            var url = '/api/posts/get-post-by-page/';
            var data = {
                page: page
            };
            $.get(url, data, function(data) {})
                .done(function(data) {
                    $(".container").html(data);
                    $.globalEval($(".comment-count-js").html());
                    loadersCss.initLoaderCss();
                    history.pushState({}, '', '/archives/?page=' + page);
                    prefetchPage();
                });
        }

        function updateContainerByCache(page) {
            $(".container").html(pageCache[page]);
            $.globalEval($(".comment-count-js").html());
            loadersCss.initLoaderCss();
            history.pushState({}, '', '/archives/?page=' + page);
            prefetchPage();
        }

        $(document).on("click", "li a.page", function() {
            var page = $(this).html();

            if (page in pageCache) {
                updateContainerByCache(page);
            } else {
                updateContainerByPage(page);
            }
            window.scrollTo(0, document.body.scrollHeight);
            return false;
        });

        $(document).on("click", "li a.page-previous, li a.page-next", function() {
            var page = $(this).data("page");

            if (page in pageCache) {
                updateContainerByCache(page);
            } else {
                updateContainerByPage(page);
            }
            window.scrollTo(0, document.body.scrollHeight);
            return false;
        });
    }

    function bindWindowScrollHandler() {
        $(window).on("scroll", function() {
            if ($(".post").length > 1) {
                if ($(window).scrollTop() + $(window).height() > $(document).height() - 400) {
                    $(window).unbind("scroll");
                    loadMorePosts();
                }
            }
        });
    }

    function getLastPostName() {
        var lastPost = $("#archives").children().last();
        var href = lastPost.children(".post-title").children().prop("href");
        var postName = href.split("/").pop();
        // postName = postName.slice(0, postName.indexOf("#"));

        return postName;
    }

    function loadMorePosts() {
        var url = "/api/posts/get-lastest-posts-by-name/";
        var data = {
            "since_name": getLastPostName()
        };

        $.getJSON(url, data, function(data) {
                console.log(data['status']);
            })
            .done(function(data) {
                $("#archives").append(data['data']);
            })
            .always(function() {
                $(window).bind('scroll', windowScrollHandler);
            });
    }

    // 键盘方向键的交互
    function bindKeyboardMove() {
        var $body = $("body");
        var postCollect = [];

        updatePostCollect();
        bindKeyboardHandler();

        function updatePostCollect() {
            postCollect = [];
            $("#archives > div").each(function(idx, ele) {
                postCollect.push($(ele).position()["top"]);
            });
        }

        function getCurrentPostIdx() {
            var current = getCurrentPostion();

            console.log(current);
            console.log(postCollect)

            for (var i = postCollect.length; i >= 0; i--) {
                if (postCollect[i] <= current || i == 0) {
                    return i;
                }
            }
        }

        function getCurrentPostion() {
            return $body.scrollTop();
        }

        function bindKeyboardHandler() {
            $body.on("keydown", function(e) {
                if (e.keyCode == 38) {
                    postMoveHandler("up");
                } else if (e.keyCode == 40) {
                    postMoveHandler("down");
                }
                return false;
            })
        }

        function postMoveHandler(direction) {
            var currentPosition = getCurrentPostion();
            var currentPostIdx = getCurrentPostIdx();
            var curentPostPostion = postCollect[currentPostIdx];

            if (direction == "up") {
                if (Math.abs(curentPostPostion - currentPosition) > 10) {
                    $body.animate({
                        scrollTop: curentPostPostion
                    });
                    return false;
                }

                if (currentPostIdx == 0) {
                    return false;
                }

                // move to forward post
                $body.animate({
                    scrollTop: postCollect[currentPostIdx - 1]
                });

            } else if (direction == "down") {
                if (currentPostIdx == postCollect.length - 1) {
                    return false;
                }
                // move to next post
                $body.animate({
                    scrollTop: postCollect[currentPostIdx + 1]
                });
            }
        }
    }
});<commit_msg>#26: fix duplicate event listerner<commit_after>$(function() {
    var $body = $("body");
    var pageCache = {};
    var postCollect = [];

    // bindWindowScrollHandler();
    bindChangePage();
    initPage();

    function prefetchPage() {
        // load pages
        $(".archives.page-nav .page").each(function(idx, ele) {
            var $ele = $(ele);
            var page = $ele.html();
            var url = $ele.attr("href");

            if (!pageCache.hasOwnProperty(page)) {
                $.get(url, function(data) {})
                    .done(function(data) {
                        pageCache[page] = data;
                    });
            }
        });
    }

    function initPage() {
        prefetchPage();
        bindKeyboardMove();
    }

    function bindChangePage() {
        function updateContainerByPage(page) {
            var url = '/api/posts/get-post-by-page/';
            var data = {
                page: page
            };
            $.get(url, data, function(data) {})
                .done(function(data) {
                    $(".container").html(data);
                    $.globalEval($(".comment-count-js").html());
                    loadersCss.initLoaderCss();
                    history.pushState({}, '', '/archives/?page=' + page);
                    initPage();
                });
        }

        function updateContainerByCache(page) {
            $(".container").html(pageCache[page]);
            $.globalEval($(".comment-count-js").html());
            loadersCss.initLoaderCss();
            history.pushState({}, '', '/archives/?page=' + page);
            initPage();
        }

        $(document).on("click", "li a.page", function() {
            var page = $(this).html();

            if (page in pageCache) {
                updateContainerByCache(page);
            } else {
                updateContainerByPage(page);
            }
            window.scrollTo(0, document.body.scrollHeight);
            return false;
        });

        $(document).on("click", "li a.page-previous, li a.page-next", function() {
            var page = $(this).data("page");

            if (page in pageCache) {
                updateContainerByCache(page);
            } else {
                updateContainerByPage(page);
            }
            window.scrollTo(0, document.body.scrollHeight);
            return false;
        });
    }

    function bindWindowScrollHandler() {
        $(window).on("scroll", function() {
            if ($(".post").length > 1) {
                if ($(window).scrollTop() + $(window).height() > $(document).height() - 400) {
                    $(window).unbind("scroll");
                    loadMorePosts();
                }
            }
        });
    }

    function getLastPostName() {
        var lastPost = $("#archives").children().last();
        var href = lastPost.children(".post-title").children().prop("href");
        var postName = href.split("/").pop();
        // postName = postName.slice(0, postName.indexOf("#"));

        return postName;
    }

    function loadMorePosts() {
        var url = "/api/posts/get-lastest-posts-by-name/";
        var data = {
            "since_name": getLastPostName()
        };

        $.getJSON(url, data, function(data) {
                console.log(data['status']);
            })
            .done(function(data) {
                $("#archives").append(data['data']);
            })
            .always(function() {
                $(window).bind('scroll', windowScrollHandler);
            });
    }

    // 键盘方向键的交互
    function bindKeyboardMove() {
        updatePostCollect();
        bindKeyboardHandler();

        function updatePostCollect() {
            postCollect = [];
            $("#archives > div").each(function(idx, ele) {
                postCollect.push($(ele).position()["top"]);
            });
        }
    }

    function getCurrentPostIdx() {
        var current = getCurrentPostion();

        for (var i = postCollect.length; i >= 0; i--) {
            if (postCollect[i] <= current || i == 0) {
                return i;
            }
        }
    }

    function getCurrentPostion() {
        return $body.scrollTop();
    }

    function bindKeyboardHandler() {
        $body.off("keydown", keybordHandler);
        $body.on("keydown", keybordHandler);

    }

    function keybordHandler(e) {
        if (e.keyCode == 38) {
            postMoveHandler("up");
            return false;
        } else if (e.keyCode == 40) {
            postMoveHandler("down");
            return false;
        }
    }

    function postMoveHandler(direction) {
        console.log("postMoveHandler for direction " + direction);

        var currentPosition = getCurrentPostion();
        var currentPostIdx = getCurrentPostIdx();
        var curentPostPostion = postCollect[currentPostIdx];

        if (direction == "up") {
            if (Math.abs(curentPostPostion - currentPosition) > 10) {
                $body.animate({
                    scrollTop: curentPostPostion
                });
                return false;
            }

            if (currentPostIdx == 0) {
                return false;
            }

            // move to forward post
            $body.animate({
                scrollTop: postCollect[currentPostIdx - 1]
            }, 200);

        } else if (direction == "down") {
            if (currentPostIdx == postCollect.length - 1) {
                return false;
            }
            // move to next post
            $body.animate({
                scrollTop: postCollect[currentPostIdx + 1]
            }, 200);
        }
    }

});<|endoftext|>


<commit_before>// DecentCMS (c) 2015 Bertrand Le Roy, under MIT. See LICENSE.txt for licensing details.
'use strict';
var path = require('path');
var fs = require('fs');
var async = require('async');

/**
 * An in-memory index implementation with file storage suitable for small sites.
 * @param {object} scope The scope.
 * @param {RegExp|string} [idFilter] A regular expression that validates
 *   content item ids before they are read and indexed.
 * @param {Function} map The map function takes a content item and returns
 *   an array of index entries, a single index entry, or null.
 *   An index entry should have an id property.
 *   The index will automatically add an `itemId` property set to be the id of
 *   the item that was used to build the index entries.
 * @param {Function} [orderBy] The function that defines the order
 *   on which the index entry should be sorted.
 *   It takes two index entries A and B, and returns -1 if A comes before B,
 *   and +1 if A comes after B.
 * @constructor
 */
function FileIndex(scope, idFilter, map, orderBy) {
  if (typeof(idFilter) === 'function') {
    orderBy = map;
    map = idFilter;
    idFilter = null;
  }
  this.scope = scope;
  this.idFilter = idFilter;
  this.map = map;
  this.orderBy = orderBy;
  this.name = FileIndex._toName(map, orderBy);
  this._unsortedIndex = null;
  this._index = null;

  // Check if a file exists, and if it does, load it
  var shell = this.scope.require('shell');
  var indexPath = path.resolve(shell.rootPath, 'index');
  if (!fs.existsSync(indexPath)) {
    fs.mkdirSync(indexPath);
  }
  var thatIndexPath = path.join(indexPath, this.name) + '.json';
  if (fs.existsSync(thatIndexPath)) {
    this._index = require(thatIndexPath);
  }
  else {
    // Otherwise, start building it
    this.build();
  }
}

/**
 * Generates a valid identifier from one or several objects,
 * using their string form.
 * @param {Function[]} [arguments] The function for which a name is needed.
 * @returns {string} A valid name built from the objects passed in.
 */
FileIndex._toName = FileIndex.prototype._toName = function toName() {
  var objectOrFunctionToName = function objectOrFunctionToName(obj) {
    return obj
      ? (obj.name || 'i') + obj.toString()
        .split('')
        .reduce(function(a, b){
          a=((a << 5) - a) + b.charCodeAt(0);
          return a & a;
        }, 0)
      : '';
  };
  return Array.prototype.slice.apply(arguments)
    .map(objectOrFunctionToName)
    .join('-');
};

/**
 * Filters the index with a where clause.
 * @param {Function} where The where function. It takes an index entry,
 *   and returns true if the entry should be included.
 * @param {Number} [start] The index of the first entry to be returned
 *   that evaluates true from the where clause.
 * @param {Number} [count] The number of entries to return.
 *   Omit if an unlimited number of items can be returned.
 * @param {Function} done The callback, that takes the array of index
 * entries satisfying the where clause and within the range as its
 * parameter.
 */
FileIndex.prototype.filter = function filter(where, start, count, done) {
  if (arguments.length == 2) {
    done = start;
    start = 0;
    count = null;
  }
  else if (arguments.length == 3) {
    done = count;
    count = null;
  }
  start = start || 0;
  var index = this._index || [];
  var results = [];
  for (var i = 0, j = 0; i < index.length && (!count || j < start + count); i++) {
    var entry = index[i];
    if (where(entry)) {
      if (j >= start) {
        results.push(entry);
      }
      j++;
    }
  }
  done(results);
};

/**
 * Reduces the index to an aggregated object.
 * @param {Function} [where] A condition on the index entries.
 * @param {Function} reduce The reduce function. It takes the previous
 *   value, the entry to process, and the index of the entry.
 *   It returns the new value.
 * @param {*} initialValue The initial value or seed of the aggregation.
 * @param {Function} done The callback, that takes the aggregated value
 * of index entries satisfying the where clause.
 */
FileIndex.prototype.reduce = function reduce(where, reduce, initialValue, done) {
  var index = this._index || [];
  if (arguments.length === 3) {
    done = initialValue;
    initialValue = reduce;
    reduce = where;
    where = null;
    done(index.reduce(reduce, initialValue));
    return;
  }
  var val = initialValue;
  for (var i = 0; i < index.length; i++) {
    var entry = index[i];
    if (where(entry)) {
      val = reduce(val, entry, i);
    }
  }
  done(val);
};

/**
 * Adds index entries to the provided internal index.
 * @param {Array} index The internal index array to which the entries
 *   will be added.
 * @param {Array|object|null} indexEntries The result of a map call.
 * @param {string} id The id of the item that was mapped.
 */
FileIndex.prototype._addToIndex = function addToIndex(index, indexEntries, id, sorted) {
  var self = this;
  if (indexEntries) {
    if (!Array.isArray(indexEntries)) {
      indexEntries = [indexEntries];
    }
    indexEntries.forEach(function addItemIdToEachEntry(entry) {
      entry.itemId = id;
    });
    if (sorted && self.orderBy) {
      // Insert the new entries
      indexEntries.forEach(function(newEntry) {
        for (var i = 0, existingEntry = index[0];
             i < index.length; i++, existingEntry = index[i]) {
          if (self.orderBy(existingEntry, newEntry) === 1) {
            index.splice(i, 0, newEntry);
            break;
          }
        }
      });
    }
    else {
      Array.prototype.push.apply(index, indexEntries);
    }
  }
};

/**
 * Builds or re-builds the index.
 * Having called that method does not mean that the index
 * will be filled on the next instruction, as this works
 * asynchronously.
 */
FileIndex.prototype.build = function build() {
  var self = this;
  var unsortedIndex = self._unsortedIndex = [];
  var context = {
    scope: self.scope,
    idFilter: self.idFilter
  };
  var stores = self.scope.getServices('content-enumerator');
  async.forEach(stores, function forEachStore(store, next) {
    var iterate = store.getItemEnumerator(context);
    var iterator = function forEachItem(err, item) {
      if (err) {
        next(err);
        return;
      }
      if (item) {
        var indexEntries = self.map(item);
        self._addToIndex(unsortedIndex, indexEntries, item.id);
        iterate(iterator);
      }
      else {
        next();
      }
    };
    iterate(iterator)
  }, function() {
    // We have all the items. Now sort.
    self._index = unsortedIndex.sort(self.orderBy);
    self._unsortedIndex = null;
    // And finally, persist.
    self._persistIndex();
  });
};

/**
 * Persists the index to disk.
 * @private
 */
FileIndex.prototype._persistIndex = function() {
  var shell = this.scope.require('shell');
  var indexPath = path.resolve(shell.rootPath, 'index');
  if (!fs.existsSync(indexPath)) {
    fs.mkdirSync(indexPath);
  }
  var thatIndexPath = path.join(indexPath, this.name);
  fs.writeFileSync(thatIndexPath + '.json', JSON.stringify(this._index, null, 0));
};

/**
 * Removes existing entries for a specific item id from an internal index.
 * @param {Array} index The internal index.
 * @param {Number} itemId The item id to remove.
 * @returns {boolean} Whether the itemId was present in the index.
 */
FileIndex.prototype._removeExistingEntries = function removeExistingEntries(index, itemId) {
  var wasIndexed = false;
  // Search and remove the already existing index entries
  for (var i = 0; i < index.length;) {
    var entry = index[i];
    if (entry.itemId === itemId) {
      index.splice(i, 1);
      wasIndexed = true;
    }
    else {
      i++;
    }
  }
  return wasIndexed;
};

/**
 * Updates the index with the results of mapping the provided item.
 * @param {object} item The item to index.
 */
FileIndex.prototype.updateWith = function updateWith(item) {
  // Don't do anything if the id doesn't satisfy the id filter.
  if (this.idFilter && !this.idFilter.test(item.id)) return;
  // Get index entries for this item.
  var indexEntries = this.map(item);
  if (this._unsortedIndex) {
    // uh oh, indexing is in progress. Let's see if that particular item
    // was already indexed.
    var wasIndexed = this._removeExistingEntries(this._unsortedIndex, item.id);
    // If it wasn't already indexed, let it be, it will eventually.
    // Otherwise, let's add it back.
    if (wasIndexed) {
      this._addToIndex(this._unsortedIndex, indexEntries, item.id);
    }
  }
  if (this._index) {
    // Do the same with the index currently in use.
    this._removeExistingEntries(this._index, item.id);
    this._addToIndex(this._index, indexEntries, item.id, true);
  }
};

/**
 * Remove entries corresponding to the provided item from the index.
 * @param {object} item The content item to remove.
 */
FileIndex.prototype.remove = function remove(item) {
  if (this._unsortedIndex) this._removeExistingEntries(this._unsortedIndex, item.id);
  if (this._index) this._removeExistingEntries(this._index, item.id);
};

/**
 * Gets the current progress of the indexing process.
 * @returns {Number} The number of entries that have already been
 *   added to the index. Once the indexing process is finished, the
 *   number of index entries is returned.
 */
FileIndex.prototype.getProgress = function getProgress() {
  var unsortedIndex = this._unsortedIndex;
  if (unsortedIndex) return unsortedIndex.length;
  if (this._index) return this._index.length;
  return 0;
};

/**
 * Gets the number of entries available in the index at the time
 * the function is called. To know how many entries have been
 * added to the index, but that are not necessarily available
 * for querying yet, use getProgress.
 * @returns {Number} The number of entries in the index.
 */
FileIndex.prototype.getLength = function getLength() {
  return this._index ? this._index.length : 0;
};

/**
 * Creates and caches index objects.
 * @param {object} scope The scope.
 * @constructor
 */
function FileIndexFactory(scope) {
  this.scope = scope;
  this.indexes = {};
}
FileIndexFactory.feature = 'file-index';
FileIndexFactory.service = 'index-store';
FileIndexFactory.scope = 'shell';

/**
 * Gets or creates the index for the provided map and order by functions.
 * @param {RegExp|string} [idFilter] A regular expression that validates
 *   content item ids before they are read and indexed.
 * @param {Function} map The map function. It takes a content item and
 *   returns null, an index entry, or an array of index entries.
 * @param {Function} [orderBy] The function that defines the order
 *   on which the index entries should be sorted.
 *   It takes two index entries A and B, and returns -1 if A comes before B,
 *   zero if they are at the same sort order, and +1 if A comes after B.
 *   It is recommended to name the order function.
 * @returns {object} The index object.
 */
FileIndexFactory.prototype.getIndex = function getIndex(idFilter, map, orderBy) {
  var name = FileIndex._toName(idFilter, map, orderBy);
  if (this.indexes[name]) return this.indexes[name];
  return this.indexes[name] = new FileIndex(this.scope, idFilter, map, orderBy);
};

FileIndexFactory._toName = FileIndex._toName;

module.exports = FileIndexFactory;<commit_msg>Fix order by to work correctly with multiple sort criteria. Delay index construction.<commit_after>// DecentCMS (c) 2015 Bertrand Le Roy, under MIT. See LICENSE.txt for licensing details.
'use strict';
var path = require('path');
var fs = require('fs');
var async = require('async');

/**
 * An in-memory index implementation with file storage suitable for small sites.
 * @param {object} scope The scope.
 * @param {RegExp|string} [idFilter] A regular expression that validates
 *   content item ids before they are read and indexed.
 * @param {Function} map The map function takes a content item and returns
 *   an array of index entries, a single index entry, or null.
 *   An index entry should have an id property.
 *   The index will automatically add an `itemId` property set to be the id of
 *   the item that was used to build the index entries.
 * @param {Function} [orderBy] The function that defines the order
 *   on which the index entry should be sorted.
 *   The sort order can be a simple string, date, number, or it can be an array,
 *   in which case the items in the array will be used one after the other.
 *   It takes an index entry, and returns the sort order.
 * @constructor
 */
function FileIndex(scope, idFilter, map, orderBy) {
  if (typeof(idFilter) === 'function') {
    orderBy = map;
    map = idFilter;
    idFilter = null;
  }
  this.scope = scope;
  this.idFilter = idFilter;
  this.map = map;
  this.orderBy = orderBy;
  this.name = FileIndex._toName(map, orderBy);
  this._unsortedIndex = null;
  this._index = null;

  // Check if a file exists, and if it does, load it
  var shell = this.scope.require('shell');
  var indexPath = path.resolve(shell.rootPath, 'index');
  if (!fs.existsSync(indexPath)) {
    fs.mkdirSync(indexPath);
  }
  var thatIndexPath = this.indexPath = path.join(indexPath, this.name) + '.json';
  if (fs.existsSync(thatIndexPath)) {
    this._index = require(thatIndexPath);
  }
}

/**
 * Generates a valid identifier from one or several objects,
 * using their string form.
 * @param {Function[]} [arguments] The function for which a name is needed.
 * @returns {string} A valid name built from the objects passed in.
 */
FileIndex._toName = FileIndex.prototype._toName = function toName() {
  var objectOrFunctionToName = function objectOrFunctionToName(obj) {
    return obj
      ? (obj.name || 'i') + obj.toString()
        .split('')
        .reduce(function(a, b){
          a=((a << 5) - a) + b.charCodeAt(0);
          return a & a;
        }, 0)
      : '';
  };
  return Array.prototype.slice.apply(arguments)
    .map(objectOrFunctionToName)
    .join('-');
};

/**
 * Filters the index with a where clause.
 * @param {Function} where The where function. It takes an index entry,
 *   and returns true if the entry should be included.
 * @param {Number} [start] The index of the first entry to be returned
 *   that evaluates true from the where clause.
 * @param {Number} [count] The number of entries to return.
 *   Omit if an unlimited number of items can be returned.
 * @param {Function} done The callback, that takes the array of index
 * entries satisfying the where clause and within the range as its
 * parameter.
 */
FileIndex.prototype.filter = function filter(where, start, count, done) {
  if (arguments.length == 2) {
    done = start;
    start = 0;
    count = null;
  }
  else if (arguments.length == 3) {
    done = count;
    count = null;
  }
  start = start || 0;
  var index = this._index || [];
  var results = [];
  for (var i = 0, j = 0; i < index.length && (!count || j < start + count); i++) {
    var entry = index[i];
    if (where(entry)) {
      if (j >= start) {
        results.push(entry);
      }
      j++;
    }
  }
  done(results);
};

/**
 * Reduces the index to an aggregated object.
 * @param {Function} [where] A condition on the index entries.
 * @param {Function} reduce The reduce function. It takes the previous
 *   value, the entry to process, and the index of the entry.
 *   It returns the new value.
 * @param {*} initialValue The initial value or seed of the aggregation.
 * @param {Function} done The callback, that takes the aggregated value
 * of index entries satisfying the where clause.
 */
FileIndex.prototype.reduce = function reduce(where, reduce, initialValue, done) {
  var index = this._index || [];
  if (arguments.length === 3) {
    done = initialValue;
    initialValue = reduce;
    reduce = where;
    where = null;
    done(index.reduce(reduce, initialValue));
    return;
  }
  var val = initialValue;
  for (var i = 0; i < index.length; i++) {
    var entry = index[i];
    if (where(entry)) {
      val = reduce(val, entry, i);
    }
  }
  done(val);
};

FileIndex.prototype._compare = function compare(a, b) {
  a = this.orderBy(a);
  b = this.orderBy(b);
  a = Array.isArray(a) ? a : [a];
  b = Array.isArray(b) ? b : [b];
  for (var i = 0; i < a.length && i < b.length; i++) {
    var ai = a[i];
    var bi = b[i];
    if ((!ai && bi) || ai < bi) return -1;
    if ((!bi && ai) || bi < ai) return 1;
  }
  return a.length - b.length;
};

/**
 * Adds index entries to the provided internal index.
 * @param {Array} index The internal index array to which the entries
 *   will be added.
 * @param {Array|object|null} indexEntries The result of a map call.
 * @param {string} id The id of the item that was mapped.
 */
FileIndex.prototype._addToIndex = function addToIndex(index, indexEntries, id, sorted) {
  var self = this;
  if (indexEntries) {
    if (!Array.isArray(indexEntries)) {
      indexEntries = [indexEntries];
    }
    indexEntries.forEach(function addItemIdToEachEntry(entry) {
      entry.itemId = id;
    });
    if (sorted && self.orderBy) {
      // Insert the new entries
      indexEntries.forEach(function(newEntry) {
        for (var i = 0, existingEntry = index[0];
             i < index.length; i++, existingEntry = index[i]) {
          if (self._compare(existingEntry, newEntry) > 0) {
            index.splice(i, 0, newEntry);
            break;
          }
        }
      });
    }
    else {
      Array.prototype.push.apply(index, indexEntries);
    }
  }
};

/**
 * Builds or re-builds the index.
 * Having called that method does not mean that the index
 * will be filled on the next instruction, as this works
 * asynchronously.
 */
FileIndex.prototype.build = function build() {
  var self = this;
  var log = self.scope.require('log');
  var unsortedIndex = self._unsortedIndex = [];
  var context = {
    scope: self.scope,
    idFilter: self.idFilter
  };
  var stores = self.scope.getServices('content-enumerator');
  async.forEach(stores, function forEachStore(store, next) {
    var iterate = store.getItemEnumerator(context);
    var iterator = function forEachItem(err, item) {
      if (err) {
        log.error('Item enumeration failed.', {item: item ? item.id : 'unknown', iterating: iterate.name})
        next(err);
        return;
      }
      if (item) {
        log.info('Indexing item', {item: item.id});
        var indexEntries = self.map(item);
        self._addToIndex(unsortedIndex, indexEntries, item.id);
        iterate(iterator);
      }
      else {
        next();
      }
    };
    iterate(iterator)
  }, function() {
    // We have all the items. Now sort.
    self._index = self.orderBy ? unsortedIndex.sort(self._compare.bind(self)) : unsortedIndex;
    self._unsortedIndex = null;
    // And finally, persist.
    self._persistIndex();
  });
};

/**
 * Persists the index to disk.
 * @private
 */
FileIndex.prototype._persistIndex = function() {
  fs.writeFileSync(this.indexPath, JSON.stringify(this._index, null, 2));
};

/**
 * Removes existing entries for a specific item id from an internal index.
 * @param {Array} index The internal index.
 * @param {Number} itemId The item id to remove.
 * @returns {boolean} Whether the itemId was present in the index.
 */
FileIndex.prototype._removeExistingEntries = function removeExistingEntries(index, itemId) {
  var wasIndexed = false;
  // Search and remove the already existing index entries
  for (var i = 0; i < index.length;) {
    var entry = index[i];
    if (entry.itemId === itemId) {
      index.splice(i, 1);
      wasIndexed = true;
    }
    else {
      i++;
    }
  }
  return wasIndexed;
};

/**
 * Updates the index with the results of mapping the provided item.
 * @param {object} item The item to index.
 */
FileIndex.prototype.updateWith = function updateWith(item) {
  // Don't do anything if the id doesn't satisfy the id filter.
  if (this.idFilter && !this.idFilter.test(item.id)) return;
  // Get index entries for this item.
  var indexEntries = this.map(item);
  if (this._unsortedIndex) {
    // uh oh, indexing is in progress. Let's see if that particular item
    // was already indexed.
    var wasIndexed = this._removeExistingEntries(this._unsortedIndex, item.id);
    // If it wasn't already indexed, let it be, it will eventually.
    // Otherwise, let's add it back.
    if (wasIndexed) {
      this._addToIndex(this._unsortedIndex, indexEntries, item.id);
    }
  }
  if (this._index) {
    // Do the same with the index currently in use.
    this._removeExistingEntries(this._index, item.id);
    this._addToIndex(this._index, indexEntries, item.id, true);
    this._persistIndex();
  }
};

/**
 * Remove entries corresponding to the provided item from the index.
 * @param {object} item The content item to remove.
 */
FileIndex.prototype.remove = function remove(item) {
  if (this._unsortedIndex) this._removeExistingEntries(this._unsortedIndex, item.id);
  if (this._index) {
    this._removeExistingEntries(this._index, item.id);
    this._persistIndex();
  }
};

/**
 * Gets the current progress of the indexing process.
 * @returns {Number} The number of entries that have already been
 *   added to the index. Once the indexing process is finished, the
 *   number of index entries is returned.
 */
FileIndex.prototype.getProgress = function getProgress() {
  var unsortedIndex = this._unsortedIndex;
  if (unsortedIndex) return unsortedIndex.length;
  if (this._index) return this._index.length;
  return 0;
};

/**
 * Gets the number of entries available in the index at the time
 * the function is called. To know how many entries have been
 * added to the index, but that are not necessarily available
 * for querying yet, use getProgress.
 * @returns {Number} The number of entries in the index.
 */
FileIndex.prototype.getLength = function getLength() {
  return this._index ? this._index.length : 0;
};

/**
 * Creates and caches index objects.
 * @param {object} scope The scope.
 * @constructor
 */
function FileIndexFactory(scope) {
  this.scope = scope;
  this.indexes = {};
}
FileIndexFactory.feature = 'file-index';
FileIndexFactory.service = 'index-store';
FileIndexFactory.scope = 'shell';

/**
 * Gets or creates the index for the provided map and order by functions.
 * @param {RegExp|string} [idFilter] A regular expression that validates
 *   content item ids before they are read and indexed.
 * @param {Function} map The map function. It takes a content item and
 *   returns null, an index entry, or an array of index entries.
 * @param {Function} [orderBy] The function that defines the order
 *   on which the index entries should be sorted.
 *   It takes an index entry, and returns the sort order.
 *   The sort order can be a simple string, date, number, or it can be an array,
 *   in which case the items in the array will be used one after the other.
 *   It is recommended to name the order function.
 * @returns {object} The index object.
 */
FileIndexFactory.prototype.getIndex = function getIndex(idFilter, map, orderBy) {
  var name = FileIndex._toName(idFilter, map, orderBy);
  if (this.indexes[name]) return this.indexes[name];
  var index = this.indexes[name] = new FileIndex(this.scope, idFilter, map, orderBy);
  if (!index._index && !index._unsortedIndex) {
    process.nextTick(index.build.bind(index));
  }
  return index;
};

FileIndexFactory._toName = FileIndex._toName;

module.exports = FileIndexFactory;<|endoftext|>


<commit_before>/*File: patch_profil.js
 *
 * Copyright (c) 2013-2016
 * Centre National d’Enseignement à Distance (Cned), Boulevard Nicephore Niepce, 86360 CHASSENEUIL-DU-POITOU, France
 * (direction-innovation@cned.fr)
 *
 * GNU Affero General Public License (AGPL) version 3.0 or later version
 *
 * This file is part of a program which is free software: you can
 * redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */
'use strict';

var mongoose = require('mongoose'), ProfilTag = mongoose.model('ProfilTag'), Profil = mongoose.model('Profil'), UserProfil = mongoose.model('UserProfil'), Tags = mongoose.model('Tag');

/**
 * Create default profil
 */
function newProfilParDefaut() {
    var newProfilTag = [ {
        'tag' : 'Titre 1',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Gras',
        'coloration' : 'Colorer les lignes RBV',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Titre 2',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Gras',
        'coloration' : 'Colorer les mots',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Titre 3',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Titre 4',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Gras',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Paragraphe',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Citation',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Liste de niveau 1',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '18',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Colorer les lignes RBV',
        'spaceCharSelected' : 1,
        'spaceSelected' : 2,
    }, {
        'tag' : 'Pied de page',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Entête de page',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Sous-titre 1',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Gras',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Annotation',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Légende',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Colorer les lignes RBV',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Sous-titre 2',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    } ];

    var newProfil = {
        'nom' : 'Accessidys par défaut',
        'descriptif' : 'Ce profil d\'adaptation est proposé par défaut par l\'application Accessidys.',
        'owner' : 'scripted',
    };

    var profile = new Profil(newProfil);
    profile.save(function(err) {
        if (err) {
            console.log('erreur creating profile.')
        } else {
            var userProfil = new UserProfil({
                'profilID' : profile._id,
                'userID' : profile.owner,
                'favoris' : false,
                'actuel' : true,
                'default' : true
            });
            userProfil.save(function(err) {
                if (err) {
                    console.log('error creating user profil for default profil')
                } else {
                    Tags.find({}, function(err, tags) {
                        if (tags) {
                            for (var i = 0; i < tags.length; i++) {
                                for (var j = 0; j < newProfilTag.length; j++) {
                                    if (newProfilTag[j].tag.indexOf(tags[i].libelle) > -1) {
                                        newProfilTag[j].tag = tags[i]._id;
                                        newProfilTag[j].profil = profile._id;
                                        var profilTag = new ProfilTag(newProfilTag[j]);
                                        profilTag.save(function(err) {
                                            if (err) {
                                                console.log('erreur saving profil tag');
                                            }
                                        });
                                        newProfilTag.splice(j, 1);
                                        break;
                                    }
                                }
                            }
                        }
                    });
                }
            });
        }
    });

};

/**
 * Update profiles sizes according to new profil's scales
 */
function updateAllProfilPoliceSize() {
    ProfilTag.find({}, function(err, foundItem) {
        if (foundItem) {
            for (var i = 0; i < foundItem.length; i++) {
                switch (foundItem[i].taille) {
                case '1':
                    foundItem[i].taille = 8;
                    break;
                case '2':
                    foundItem[i].taille = 9;
                    break;
                case '3':
                    foundItem[i].taille = 10;
                    break;
                case '4':
                    foundItem[i].taille = 11;
                    break;
                case '5':
                    foundItem[i].taille = 12;
                    break;
                case '6':
                    foundItem[i].taille = 14;
                    break;
                case '7':
                    foundItem[i].taille = 16;
                    break;
                case '8':
                    foundItem[i].taille = 18;
                    break;
                case '9':
                    foundItem[i].taille = 22;
                    break;
                case '10':
                    foundItem[i].taille = 24;
                    break;
                default:
                    foundItem[i].taille = 10;
                    break;
                }
                var newSpaceSelected = 0 + (foundItem[i].spaceSelected - 1) * 0.18;
                var newSpaceCharSelected = 0 + (foundItem[i].spaceCharSelected - 1) * 0.12;

                var newTaille = foundItem[i].taille / 12;
                var newInterLigne = 1.286 + (foundItem[i].interligne - 1) * 0.18;

                foundItem[i].texte = '

';
                ProfilTag.findByIdAndUpdate(foundItem[i]._id, foundItem[i], function(err, itemEdit) {
                });
            }
        }
    });
};

function executePatchProfil() {
    Profil.findOne({
        'nom' : 'Accessidys par défaut',
        'descriptif' : 'Ce profil d\'adaptation est proposé par défaut par l\'application Accessidys.',
        'owner' : 'scripted',
    }, function(err, item) {
        if (!item) {
            newProfilParDefaut();
        }
    });

    ProfilTag.findOne({
        taille : '24',
    }, function(err, foundItem) {
        if (!foundItem) {
            updateAllProfilPoliceSize();
        }
    });

};
executePatchProfil();
<commit_msg>Script update police.<commit_after>/*File: patch_profil.js
 *
 * Copyright (c) 2013-2016
 * Centre National d’Enseignement à Distance (Cned), Boulevard Nicephore Niepce, 86360 CHASSENEUIL-DU-POITOU, France
 * (direction-innovation@cned.fr)
 *
 * GNU Affero General Public License (AGPL) version 3.0 or later version
 *
 * This file is part of a program which is free software: you can
 * redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */
'use strict';

var mongoose = require('mongoose'), ProfilTag = mongoose.model('ProfilTag'), Profil = mongoose.model('Profil'), UserProfil = mongoose.model('UserProfil'), Tags = mongoose.model('Tag');

/**
 * Create default profil
 */
function newProfilParDefaut() {
    var newProfilTag = [ {
        'tag' : 'Titre 1',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Gras',
        'coloration' : 'Colorer les lignes RBV',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Titre 2',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Gras',
        'coloration' : 'Colorer les mots',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Titre 3',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Titre 4',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Gras',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Paragraphe',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Citation',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Liste de niveau 1',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '18',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Colorer les lignes RBV',
        'spaceCharSelected' : 1,
        'spaceSelected' : 2,
    }, {
        'tag' : 'Pied de page',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Entête de page',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Sous-titre 1',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Gras',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Annotation',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Légende',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Colorer les lignes RBV',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    }, {
        'tag' : 'Sous-titre 2',
        'texte' : '

',
        'profil' : '55d6db348539cb882212195a',
        'police' : 'opendyslexicregular',
        'taille' : '10',
        'interligne' : '1',
        'styleValue' : 'Normal',
        'coloration' : 'Pas de coloration',
        'spaceCharSelected' : 1,
        'spaceSelected' : 1,
    } ];

    var newProfil = {
        'nom' : 'Accessidys par défaut',
        'descriptif' : 'Ce profil d\'adaptation est proposé par défaut par l\'application Accessidys.',
        'owner' : 'scripted',
    };

    var profile = new Profil(newProfil);
    profile.save(function(err) {
        if (err) {
            console.log('erreur creating profile.')
        } else {
            var userProfil = new UserProfil({
                'profilID' : profile._id,
                'userID' : profile.owner,
                'favoris' : false,
                'actuel' : true,
                'default' : true
            });
            userProfil.save(function(err) {
                if (err) {
                    console.log('error creating user profil for default profil')
                } else {
                    Tags.find({}, function(err, tags) {
                        if (tags) {
                            for (var i = 0; i < tags.length; i++) {
                                for (var j = 0; j < newProfilTag.length; j++) {
                                    if (newProfilTag[j].tag.indexOf(tags[i].libelle) > -1) {
                                        newProfilTag[j].tag = tags[i]._id;
                                        newProfilTag[j].profil = profile._id;
                                        var profilTag = new ProfilTag(newProfilTag[j]);
                                        profilTag.save(function(err) {
                                            if (err) {
                                                console.log('erreur saving profil tag');
                                            }
                                        });
                                        newProfilTag.splice(j, 1);
                                        break;
                                    }
                                }
                            }
                        }
                    });
                }
            });
        }
    });

};

/**
 * Update profiles sizes according to new profil's scales
 */
function updateAllProfilPoliceSize(profilId) {
    ProfilTag.find({
        profil : {
            $ne : profilId
        }
    }, function(err, foundItem) {
        if (foundItem) {
            for (var i = 0; i < foundItem.length; i++) {
                switch (foundItem[i].taille) {
                case '1':
                    foundItem[i].taille = 8;
                    break;
                case '2':
                    foundItem[i].taille = 9;
                    break;
                case '3':
                    foundItem[i].taille = 10;
                    break;
                case '4':
                    foundItem[i].taille = 11;
                    break;
                case '5':
                    foundItem[i].taille = 12;
                    break;
                case '6':
                    foundItem[i].taille = 14;
                    break;
                case '7':
                    foundItem[i].taille = 16;
                    break;
                case '8':
                    foundItem[i].taille = 18;
                    break;
                case '9':
                    foundItem[i].taille = 22;
                    break;
                case '10':
                    foundItem[i].taille = 24;
                    break;
                default:
                    foundItem[i].taille = 10;
                    break;
                }
                var newSpaceSelected = 0 + (foundItem[i].spaceSelected - 1) * 0.18;
                var newSpaceCharSelected = 0 + (foundItem[i].spaceCharSelected - 1) * 0.12;

                var newTaille = foundItem[i].taille / 12;
                var newInterLigne = 1.286 + (foundItem[i].interligne - 1) * 0.18;

                foundItem[i].texte = '

';
                ProfilTag.findByIdAndUpdate(foundItem[i]._id, foundItem[i], function(err, itemEdit) {
                });
            }
        }
    });
};

function executePatchProfil() {
    Profil.findOne({
        'nom' : 'Accessidys par défaut',
        'descriptif' : 'Ce profil d\'adaptation est proposé par défaut par l\'application Accessidys.',
        'owner' : 'scripted',
    }, function(err, item) {
        if (!item) {
            newProfilParDefaut();
        } else {
            ProfilTag.findOne({
                taille : '1',
            }, function(err, foundItem) {
                if (foundItem) {
                    updateAllProfilPoliceSize(item._id);
                }
            });
        }
    });

};

executePatchProfil();
<|endoftext|>


<commit_before>var utils = require('map-tools/utils');

module.exports = function(global, that, type) {

  var addFilter = require('map-tools/addFilter')(global, that, type);

  var orderLookup = {
    ASC: 'top',
    DESC: 'bottom'
  };

  var tags = [];

  // cf has it's own state, for each dimension
  // before each new filtering we need to clear this state
  function clearAll(dimensionSet){
    var i, dimension;
    for (i in dimensionSet){

      if (dimensionSet.hasOwnProperty(i)) {
        dimension = dimensionSet[i];

        if (that[type].dataChanged === true) {
          dimension.dispose();
          addFilter(i);
        } else {
          dimension.filterAll();
        }

      }
    }
  }

  function filterByTag(query) {
    // if the search query is an array with only one item then just use that string
    if(utils.isArray(query) && query.length === 1){
      query = query[0];
    }
    if (typeof query === "string"){
      if (that[type].tags[query]) {
        return utils.toArray(that[type].tags[query]);
      } else {
        return [];
      }
    } else {
      var markers =  fetchByTag(query);
      if(typeof markers === "object"){
        markers = utils.toArray(markers);
      }
      return markers;
    }
  }

  function fetchByTag(query){
    var res; // store first set of markers to compare

    for (var i in query) {
      var tag = query[i];
      var nextTag = query[parseInt(i)+parseInt(1)];
      // null check kicks in when we get to the end of the for loop
      if(nextTag === undefined){
        return res;
      }
      res = utils.getCommonObject(that[type].tags[tag],that[type].tags[nextTag])
    }
    return res;
  }

  function filter(args, options) {

    // Return All items if no arguments are supplied
    if (typeof args === 'undefined' && typeof options === 'undefined') {
      return utils.toArray(that[type].all);
    }

    var dimension, order, limit, query;

    if (typeof args === 'string') {
      dimension = args;
    } else {
      dimension = Object.keys(args)[0];
      query = args[dimension];

      if (dimension === 'tags') {
        return filterByTag(query);
      }
    }

    clearAll(that[type].filter);

    // Add Crossfilter Dimension if it does not exist.
    if (!that[type].filter[dimension]) {
      addFilter(dimension);
    }

    order = (options && options.order && orderLookup[options.order]) ?
      orderLookup[options.order]
      : orderLookup[Object.keys(orderLookup)[0]];

    limit = (options && options.limit) ? options.limit : Infinity;

    if (typeof query === 'undefined') {
      query = null;
    }

    var result = that[type].filter[dimension].filter(query)[order](limit);

    that[type].dataChanged = false;

    if (limit === 1) {
      return result[0];
    }

    return result;

  }

  return filter;
};
<commit_msg>fixed - #268, multi tag search-  kill unreachable return<commit_after>var utils = require('map-tools/utils');

module.exports = function(global, that, type) {

  var addFilter = require('map-tools/addFilter')(global, that, type);

  var orderLookup = {
    ASC: 'top',
    DESC: 'bottom'
  };

  var tags = [];

  // cf has it's own state, for each dimension
  // before each new filtering we need to clear this state
  function clearAll(dimensionSet){
    var i, dimension;
    for (i in dimensionSet){

      if (dimensionSet.hasOwnProperty(i)) {
        dimension = dimensionSet[i];

        if (that[type].dataChanged === true) {
          dimension.dispose();
          addFilter(i);
        } else {
          dimension.filterAll();
        }

      }
    }
  }

  function filterByTag(query) {
    // if the search query is an array with only one item then just use that string
    if(utils.isArray(query) && query.length === 1){
      query = query[0];
    }
    if (typeof query === "string"){
      if (that[type].tags[query]) {
        return utils.toArray(that[type].tags[query]);
      } else {
        return [];
      }
    } else {
      var markers =  fetchByTag(query);
      if(typeof markers === "object"){
        markers = utils.toArray(markers);
      }
      return markers;
    }
  }

  function fetchByTag(query){
    var res; // store first set of markers to compare

    for (var i in query) {
      var tag = query[i];
      var nextTag = query[parseInt(i)+parseInt(1)];
      // null check kicks in when we get to the end of the for loop
      if(nextTag === undefined){
        return res;
      }
      res = utils.getCommonObject(that[type].tags[tag],that[type].tags[nextTag])
    }
  }

  function filter(args, options) {

    // Return All items if no arguments are supplied
    if (typeof args === 'undefined' && typeof options === 'undefined') {
      return utils.toArray(that[type].all);
    }

    var dimension, order, limit, query;

    if (typeof args === 'string') {
      dimension = args;
    } else {
      dimension = Object.keys(args)[0];
      query = args[dimension];

      if (dimension === 'tags') {
        return filterByTag(query);
      }
    }

    clearAll(that[type].filter);

    // Add Crossfilter Dimension if it does not exist.
    if (!that[type].filter[dimension]) {
      addFilter(dimension);
    }

    order = (options && options.order && orderLookup[options.order]) ?
      orderLookup[options.order]
      : orderLookup[Object.keys(orderLookup)[0]];

    limit = (options && options.limit) ? options.limit : Infinity;

    if (typeof query === 'undefined') {
      query = null;
    }

    var result = that[type].filter[dimension].filter(query)[order](limit);

    that[type].dataChanged = false;

    if (limit === 1) {
      return result[0];
    }

    return result;

  }

  return filter;
};
<|endoftext|>


<commit_before><commit_msg>Refactoring param-types-validation for wrap function into a private boolean method to improve readability<commit_after><|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import LinkButton from 'shared/components/linkButton/linkButton';
import styles from './imageCard.css';

class ImageCard extends Component {
  render() {
    return (

{this.props.title}:

{this.props.cardText}

            {this.props.link && <LinkButton text={this.props.buttonText} link={this.props.link} />}

    );
  }
}

ImageCard.propTypes = {
  image: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  cardText: PropTypes.string.isRequired,
  buttonText: PropTypes.string,
  link: PropTypes.string
};

ImageCard.defaultProps = {
  link: null,
  buttonText: null
}

// TODO: Uncomment buttons as routes are implemented
// NOTE: ImageCard dynamically handles button-links as optionally, so no further work required

export default ImageCard;
<commit_msg>Fix missing semicolon<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import LinkButton from 'shared/components/linkButton/linkButton';
import styles from './imageCard.css';

class ImageCard extends Component {
  render() {
    return (

{this.props.title}:

{this.props.cardText}

            {this.props.link && <LinkButton text={this.props.buttonText} link={this.props.link} />}

    );
  }
}

ImageCard.propTypes = {
  image: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  cardText: PropTypes.string.isRequired,
  buttonText: PropTypes.string,
  link: PropTypes.string
};

ImageCard.defaultProps = {
  link: null,
  buttonText: null
};

// TODO: Uncomment buttons as routes are implemented
// NOTE: ImageCard dynamically handles button-links as optionally, so no further work required

export default ImageCard;
<|endoftext|>


<commit_before>const path = Plugin.path;
const fs = Plugin.fs;
const sass = Npm.require('node-sass');
const Future = Npm.require('fibers/future');
const files = Plugin.files;

Plugin.registerCompiler({
  extensions: ['scss', 'sass'],
  archMatching: 'web'
}, () => new SassCompiler());

var toPosixPath = function (p, partialPath) {
  // Sometimes, you can have a path like \Users\IEUser on windows, and this
  // actually means you want C:\Users\IEUser
  if (p[0] === "\\" && (! partialPath)) {
    p = process.env.SystemDrive + p;
  }

  p = p.replace(/\\/g, '/');
  if (p[1] === ':' && ! partialPath) {
    // transform "C:/bla/bla" to "/c/bla/bla"
    p = '/' + p[0] + p.slice(2);
  }

  return p;
};

var convertToStandardPath = function (osPath, partialPath) {
  if (process.platform === "win32") {
    return toPosixPath(osPath, partialPath);
  }

  return osPath;
}

// CompileResult is {css, sourceMap}.
class SassCompiler extends MultiFileCachingCompiler {
  constructor() {
    super({
      compilerName: 'sass',
      defaultCacheSize: 1024*1024*10
    });
  }

  getCacheKey(inputFile) {
    return inputFile.getSourceHash();
  }

  compileResultSize(compileResult) {
    return compileResult.css.length +
      this.sourceMapSize(compileResult.sourceMap);
  }

  // The heuristic is that a file is an import (ie, is not itself processed as a
  // root) if it matches _*.sass, _*.scss
  // This can be overridden in either direction via an explicit
  // `isImport` file option in api.addFiles.
  isRoot(inputFile) {
    const fileOptions = inputFile.getFileOptions();
    if (fileOptions.hasOwnProperty('isImport')) {
      return !fileOptions.isImport;
    }

    const pathInPackage = inputFile.getPathInPackage();
    return !this.hasUnderscore(pathInPackage);
  }

  hasUnderscore(file){
    return path.basename(file)[0] === '_';
  }

  compileOneFile(inputFile, allFiles) {

    const referencedImportPaths = [];

    const self = this;

    var totalImportPath = [];
    var sourceMapPaths = ['.'+inputFile.getDisplayPath()];

    //Handle deprecation of fs.existsSYnc
    //XXX: remove when meteor is fully on node 4+
    function fileExists(file){
      if(fs.statSync){
        try{
          fs.statSync(file);
        }catch(e){
          return false;
        }
        return true;
      }else{
        return fs.existsSync(file);
      }
    }

    function addUnderscore(file){
      if(!self.hasUnderscore(file)){
        file = path.join(path.dirname(file),'_'+path.basename(file));
      }
      return file;
    }

    const getRealImportPath = function(importPath){
      const rawImportPath = importPath;
      var isAbsolute = false;

      if(importPath[0] === '/'){
        isAbsolute = true;
      }

      //SASS has a whole range of possible import files from one import statement, try each of them
      const possibleFiles = [];

      //If the referenced file has no extension, try possible extensions, starting with extension of the parent file.
      let possibleExtensions = ['scss','sass','css'];

      if(! importPath.match(/\.s?(a|c)ss$/)){
        possibleExtensions = [inputFile.getExtension()].concat(_.without(possibleExtensions,inputFile.getExtension()));
        for(const extension of possibleExtensions){
          possibleFiles.push(importPath+'.'+extension);
        }
      }else{
        possibleFiles.push(importPath);
      }

      //Try files prefixed with underscore
      for(const possibleFile of possibleFiles){
        if(! self.hasUnderscore(possibleFile)){
          possibleFiles.push(addUnderscore(possibleFile));
        }
      }

      //Try if one of the possible files exists
      for(const possibleFile of possibleFiles){
        if((isAbsolute && fileExists(possibleFile)) || (!isAbsolute && allFiles.has(possibleFile))){
            return {absolute:isAbsolute,path:possibleFile};
        }
      }

      //Nothing found...
      throw new Error(`File to import: ${rawImportPath} not found in file: ${totalImportPath[totalImportPath.length-2]}`);

    }

    //Handle import statements found by the sass compiler, used to handle cross-package imports
    const importer = function(url,prev,done){

      if(!totalImportPath.length){
        totalImportPath.push(prev);
      }

      if(totalImportPath[totalImportPath.length] !== prev){
        //backtracked, splice of part we don't need anymore
        // (XXX: this might give problems when multiple parts of the path have the same name)
        totalImportPath.splice(totalImportPath.indexOf(prev)+1,totalImportPath.length);
      }

      var importPath = url;
      for(var i = totalImportPath.length-1; i >= 0; i--){
        if(importPath[0] === '/' || importPath[0] === '{'){
          break;
        }
        importPath = path.join(path.dirname(totalImportPath[i]),importPath);
      }
      totalImportPath.push(url);

      let accPosition = importPath.indexOf('{');
      if(accPosition > -1){
        importPath = importPath.substr(accPosition,importPath.length);
      }

      try{
        const parsed = getRealImportPath(importPath);
        if (parsed.absolute) {
          sourceMapPaths.push(parsed.path);
          done({ contents: fs.readFileSync(parsed.path, 'utf8')});
        }else{
          referencedImportPaths.push(parsed.path);
          sourceMapPaths.push(decodeFilePath(parsed.path));
          done({ contents: allFiles.get(parsed.path).getContentsAsString()});
        }
      }catch(e){
        return done(e);
      }

    }

    //Start compile sass (async)
    const f = new Future;

    const options = {
      sourceMap:         true,
      sourceMapContents: true,
      sourceMapEmbed:    false,
      sourceComments:    false,
      sourceMapRoot: '.',
      indentedSyntax : inputFile.getExtension() === 'sass',
      outFile: '.'+inputFile.getBasename(),
      importer: importer,
      includePaths:      []
    };

    options.file  =  this.getAbsoluteImportPath(inputFile);

    options.data = inputFile.getContentsAsBuffer().toString('utf8');

    //If the file is empty, options.data is an empty string
    // In that case options.file will be used by node-sass,
    // which it can not read since it will contain a meteor package or app reference '{}'
    // This is one workaround, another one would be to not set options.file, in which case the importer 'prev' will be 'stdin'
    // However, this would result in problems if a file named stdn.scss would exist.
    // Not the most elegant of solutions, but it works.
    if(!options.data.trim()){
      options.data = "$fakevariable : blue;"
    }

    let output;
    try {
      sass.render(options,f.resolver());
      output = f.wait();
    } catch (e) {
      inputFile.error({
        message: `Scss compiler error: ${e.message}\n`,
        sourcePath: inputFile.getDisplayPath()
      });
      return null;
    }
    //End compile sass

    //Start fix sourcemap references
    if (output.map) {
      const map = JSON.parse(output.map.toString('utf-8'));
      map.sources = sourceMapPaths;
      output.map = map;
    }
    //End fix sourcemap references

    const compileResult = {css: output.css.toString('utf-8'), sourceMap: output.map};
    return {compileResult,referencedImportPaths};
  }

  addCompileResult(inputFile,  compileResult) {
    inputFile.addStylesheet({
      data:  compileResult.css,
      path: inputFile.getPathInPackage() + '.css',
      sourceMap:  compileResult.sourceMap
    });
  }
}

function decodeFilePath (filePath) {
  const match = filePath.match(/{(.*)}\/(.*)$/);
  if (! match)
    throw new Error('Failed to decode Less path: ' + filePath);

  if (match[1] === '') {
    // app
    return match[2];
  }

  return 'packages/' + match[1] + '/' + match[2];
}
<commit_msg>supress sourceMapUrl in output file as it is sent as a header.<commit_after>const path = Plugin.path;
const fs = Plugin.fs;
const sass = Npm.require('node-sass');
const Future = Npm.require('fibers/future');
const files = Plugin.files;

Plugin.registerCompiler({
  extensions: ['scss', 'sass'],
  archMatching: 'web'
}, () => new SassCompiler());

var toPosixPath = function (p, partialPath) {
  // Sometimes, you can have a path like \Users\IEUser on windows, and this
  // actually means you want C:\Users\IEUser
  if (p[0] === "\\" && (! partialPath)) {
    p = process.env.SystemDrive + p;
  }

  p = p.replace(/\\/g, '/');
  if (p[1] === ':' && ! partialPath) {
    // transform "C:/bla/bla" to "/c/bla/bla"
    p = '/' + p[0] + p.slice(2);
  }

  return p;
};

var convertToStandardPath = function (osPath, partialPath) {
  if (process.platform === "win32") {
    return toPosixPath(osPath, partialPath);
  }

  return osPath;
}

// CompileResult is {css, sourceMap}.
class SassCompiler extends MultiFileCachingCompiler {
  constructor() {
    super({
      compilerName: 'sass',
      defaultCacheSize: 1024*1024*10
    });
  }

  getCacheKey(inputFile) {
    return inputFile.getSourceHash();
  }

  compileResultSize(compileResult) {
    return compileResult.css.length +
      this.sourceMapSize(compileResult.sourceMap);
  }

  // The heuristic is that a file is an import (ie, is not itself processed as a
  // root) if it matches _*.sass, _*.scss
  // This can be overridden in either direction via an explicit
  // `isImport` file option in api.addFiles.
  isRoot(inputFile) {
    const fileOptions = inputFile.getFileOptions();
    if (fileOptions.hasOwnProperty('isImport')) {
      return !fileOptions.isImport;
    }

    const pathInPackage = inputFile.getPathInPackage();
    return !this.hasUnderscore(pathInPackage);
  }

  hasUnderscore(file){
    return path.basename(file)[0] === '_';
  }

  compileOneFile(inputFile, allFiles) {

    const referencedImportPaths = [];

    const self = this;

    var totalImportPath = [];
    var sourceMapPaths = ['.'+inputFile.getDisplayPath()];

    //Handle deprecation of fs.existsSYnc
    //XXX: remove when meteor is fully on node 4+
    function fileExists(file){
      if(fs.statSync){
        try{
          fs.statSync(file);
        }catch(e){
          return false;
        }
        return true;
      }else{
        return fs.existsSync(file);
      }
    }

    function addUnderscore(file){
      if(!self.hasUnderscore(file)){
        file = path.join(path.dirname(file),'_'+path.basename(file));
      }
      return file;
    }

    const getRealImportPath = function(importPath){
      const rawImportPath = importPath;
      var isAbsolute = false;

      if(importPath[0] === '/'){
        isAbsolute = true;
      }

      //SASS has a whole range of possible import files from one import statement, try each of them
      const possibleFiles = [];

      //If the referenced file has no extension, try possible extensions, starting with extension of the parent file.
      let possibleExtensions = ['scss','sass','css'];

      if(! importPath.match(/\.s?(a|c)ss$/)){
        possibleExtensions = [inputFile.getExtension()].concat(_.without(possibleExtensions,inputFile.getExtension()));
        for(const extension of possibleExtensions){
          possibleFiles.push(importPath+'.'+extension);
        }
      }else{
        possibleFiles.push(importPath);
      }

      //Try files prefixed with underscore
      for(const possibleFile of possibleFiles){
        if(! self.hasUnderscore(possibleFile)){
          possibleFiles.push(addUnderscore(possibleFile));
        }
      }

      //Try if one of the possible files exists
      for(const possibleFile of possibleFiles){
        if((isAbsolute && fileExists(possibleFile)) || (!isAbsolute && allFiles.has(possibleFile))){
            return {absolute:isAbsolute,path:possibleFile};
        }
      }

      //Nothing found...
      throw new Error(`File to import: ${rawImportPath} not found in file: ${totalImportPath[totalImportPath.length-2]}`);

    }

    //Handle import statements found by the sass compiler, used to handle cross-package imports
    const importer = function(url,prev,done){

      if(!totalImportPath.length){
        totalImportPath.push(prev);
      }

      if(totalImportPath[totalImportPath.length] !== prev){
        //backtracked, splice of part we don't need anymore
        // (XXX: this might give problems when multiple parts of the path have the same name)
        totalImportPath.splice(totalImportPath.indexOf(prev)+1,totalImportPath.length);
      }

      var importPath = url;
      for(var i = totalImportPath.length-1; i >= 0; i--){
        if(importPath[0] === '/' || importPath[0] === '{'){
          break;
        }
        importPath = path.join(path.dirname(totalImportPath[i]),importPath);
      }
      totalImportPath.push(url);

      let accPosition = importPath.indexOf('{');
      if(accPosition > -1){
        importPath = importPath.substr(accPosition,importPath.length);
      }

      try{
        const parsed = getRealImportPath(importPath);
        if (parsed.absolute) {
          sourceMapPaths.push(parsed.path);
          done({ contents: fs.readFileSync(parsed.path, 'utf8')});
        }else{
          referencedImportPaths.push(parsed.path);
          sourceMapPaths.push(decodeFilePath(parsed.path));
          done({ contents: allFiles.get(parsed.path).getContentsAsString()});
        }
      }catch(e){
        return done(e);
      }

    }

    //Start compile sass (async)
    const f = new Future;

    const options = {
      sourceMap:         true,
      sourceMapContents: true,
      sourceMapEmbed:    false,
      sourceComments:    false,
      omitSourceMapUrl:  true,
      sourceMapRoot: '.',
      indentedSyntax : inputFile.getExtension() === 'sass',
      outFile: '.'+inputFile.getBasename(),
      importer: importer,
      includePaths:      []
    };

    options.file  =  this.getAbsoluteImportPath(inputFile);

    options.data = inputFile.getContentsAsBuffer().toString('utf8');

    //If the file is empty, options.data is an empty string
    // In that case options.file will be used by node-sass,
    // which it can not read since it will contain a meteor package or app reference '{}'
    // This is one workaround, another one would be to not set options.file, in which case the importer 'prev' will be 'stdin'
    // However, this would result in problems if a file named stdn.scss would exist.
    // Not the most elegant of solutions, but it works.
    if(!options.data.trim()){
      options.data = "$fakevariable : blue;"
    }

    let output;
    try {
      sass.render(options,f.resolver());
      output = f.wait();
    } catch (e) {
      inputFile.error({
        message: `Scss compiler error: ${e.message}\n`,
        sourcePath: inputFile.getDisplayPath()
      });
      return null;
    }
    //End compile sass

    //Start fix sourcemap references
    if (output.map) {
      const map = JSON.parse(output.map.toString('utf-8'));
      map.sources = sourceMapPaths;
      output.map = map;
    }
    //End fix sourcemap references

    const compileResult = {css: output.css.toString('utf-8'), sourceMap: output.map};
    return {compileResult,referencedImportPaths};
  }

  addCompileResult(inputFile,  compileResult) {
    inputFile.addStylesheet({
      data:  compileResult.css,
      path: inputFile.getPathInPackage() + '.css',
      sourceMap:  compileResult.sourceMap
    });
  }
}

function decodeFilePath (filePath) {
  const match = filePath.match(/{(.*)}\/(.*)$/);
  if (! match)
    throw new Error('Failed to decode Less path: ' + filePath);

  if (match[1] === '') {
    // app
    return match[2];
  }

  return 'packages/' + match[1] + '/' + match[2];
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

angular.module(PKG.name + '.services')
  .constant('GLOBALS', {
    // Should be under property called 'artifactTypes' to be consistent. GLOBALS.etlBatch doesn't make much sense.
    etlBatch: 'cdap-etl-batch',
    etlRealtime: 'cdap-etl-realtime',
    // This is here because until now we don't store the aritfact information for each plugin anywhere.
    // From now we need this information to ask for backend widgets json. So if there are any published pipelines/drafts that
    // does not have artifact info of a plugin we default it to here.

    artifact: {
      default: {
        name: 'cdap-etl-lib',
        version: '3.3.0-SNAPSHOT',
        scope: 'SYSTEM'
      }
    },
    pluginTypes: {
      'cdap-etl-batch': {
        'source': 'batchsource',
        'sink': 'batchsink',
        'transform': 'transform'
      },
      'cdap-etl-realtime': {
        'source': 'realtimesource',
        'sink': 'realtimesink',
        'transform': 'transform'
      }
    },
    pluginConvert: {
      'batchsource': 'source',
      'realtimesource': 'source',
      'batchsink': 'sink',
      'realtimesink': 'sink',
      'transform': 'transform'
    },

    'en': {
      hydrator: {
        appLabel: 'Hydrator Pipeline',
        studio: {
          noConfigMessage: 'No configuration found for the plugin.',
          syntaxConfigJsonError: 'Syntax error in the configuration JSON for the plugin.',
          semanticConfigJsonError: 'Semantic error in the configuration JSON for the plugin.',
          oneSinkError: 'Please add at least one sink to your pipeline.',
          sourceRequiredFieldsError: 'Please provide required fields for the source.',
          sinkRequiredFieldsError: 'Please provide required fields for the sink.',
          transformRequiredFieldsError: 'Please provide required fields for the transform.',
          genericMissingRequiredFieldsError: 'Missing required fields.',
          pluginNameMissingRequiredFieldsError: ' is missing required fields',
          oneSourceError: 'Pipelines can only have one source. Please remove any additional sources.',
          noSourceError: 'Please add a source to your pipeline',
          nameError: 'Please name your pipeline.',
          nameValidationError: 'Pipeline names can only contain alphanumeric (\'a-z A-Z 0-9\') and underscore ( \'_\') characters. Please remove any other characters.',
          sinkBranchNodeError: 'Please connect multiple sinks to the same node.',
          atLeastOneSinkError: 'Please add a sink to your pipeline',
          branchError: 'Please remove branched connections.',
          unconnectedNodesError: 'Please connect all nodes.',
          circularConnectionError: 'Please remove the circular connection in this pipeline.',
          endSinkError: 'Please end the pipeline connections in a sink.',
          parallelConnectionError: 'Please remove parallel connections in this pipeline.',
          pluginDoesNotExist: 'This plugin does not exist: ',
          unsavedPluginMessage1: 'There are unsaved changes for node \'',
          unsavedPluginMessage2: '\'. Please save them before publishing the pipeline.',
          pipelineNameAlreadyExistError: 'This pipeline name already exist. Please choose a different name.'
        },
        wizard: {
          welcomeMessage1: 'Hydrator makes it easy to prepare data so you ',
          welcomeMessage2: 'can get down to business faster. Let\'s get started!',
          createMessage: 'ETL made simple. Hydrator offers four ways to get started.',
          createConsoleMessage: 'Click a node from the menu to place it on the canvas above.'
        },
      },
      admin: {
        templateNameExistsError: 'This template name already exists! Please choose another name.',
        pluginSameNameError: 'There is already a plugin with this name.',
        templateNameMissingError: 'Please enter a template name.'
      }
    }
  });
<commit_msg>update error message<commit_after>/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

angular.module(PKG.name + '.services')
  .constant('GLOBALS', {
    // Should be under property called 'artifactTypes' to be consistent. GLOBALS.etlBatch doesn't make much sense.
    etlBatch: 'cdap-etl-batch',
    etlRealtime: 'cdap-etl-realtime',
    // This is here because until now we don't store the aritfact information for each plugin anywhere.
    // From now we need this information to ask for backend widgets json. So if there are any published pipelines/drafts that
    // does not have artifact info of a plugin we default it to here.

    artifact: {
      default: {
        name: 'cdap-etl-lib',
        version: '3.3.0-SNAPSHOT',
        scope: 'SYSTEM'
      }
    },
    pluginTypes: {
      'cdap-etl-batch': {
        'source': 'batchsource',
        'sink': 'batchsink',
        'transform': 'transform'
      },
      'cdap-etl-realtime': {
        'source': 'realtimesource',
        'sink': 'realtimesink',
        'transform': 'transform'
      }
    },
    pluginConvert: {
      'batchsource': 'source',
      'realtimesource': 'source',
      'batchsink': 'sink',
      'realtimesink': 'sink',
      'transform': 'transform'
    },

    'en': {
      hydrator: {
        appLabel: 'Hydrator Pipeline',
        studio: {
          noConfigMessage: 'No configuration found for the plugin.',
          syntaxConfigJsonError: 'Syntax error in the configuration JSON for the plugin.',
          semanticConfigJsonError: 'Semantic error in the configuration JSON for the plugin.',
          oneSinkError: 'Please add at least one sink to your pipeline.',
          sourceRequiredFieldsError: 'Please provide required fields for the source.',
          sinkRequiredFieldsError: 'Please provide required fields for the sink.',
          transformRequiredFieldsError: 'Please provide required fields for the transform.',
          genericMissingRequiredFieldsError: 'Missing required fields.',
          pluginNameMissingRequiredFieldsError: ' is missing required fields',
          oneSourceError: 'Pipelines can only have one source. Please remove any additional sources.',
          noSourceError: 'Please add a source to your pipeline',
          nameError: 'Please name your pipeline.',
          nameValidationError: 'Pipeline names can only contain alphanumeric (\'a-z A-Z 0-9\') and underscore ( \'_\') characters. Please remove any other characters.',
          sinkBranchNodeError: 'Please connect multiple sinks to the same node.',
          atLeastOneSinkError: 'Please add a sink to your pipeline',
          branchError: 'Please remove branched connections.',
          unconnectedNodesError: 'Please connect all nodes.',
          circularConnectionError: 'Please remove the circular connection in this pipeline.',
          endSinkError: 'Please end the pipeline connections in a sink.',
          parallelConnectionError: 'Please remove parallel connections in this pipeline.',
          pluginDoesNotExist: 'This plugin does not exist: ',
          unsavedPluginMessage1: 'There are unsaved changes for node \'',
          unsavedPluginMessage2: '\'. Please save them before publishing the pipeline.',
          pipelineNameAlreadyExistError: 'A pipeline with this name already exists. Please choose a different name.'
        },
        wizard: {
          welcomeMessage1: 'Hydrator makes it easy to prepare data so you ',
          welcomeMessage2: 'can get down to business faster. Let\'s get started!',
          createMessage: 'ETL made simple. Hydrator offers four ways to get started.',
          createConsoleMessage: 'Click a node from the menu to place it on the canvas above.'
        },
      },
      admin: {
        templateNameExistsError: 'This template name already exists! Please choose another name.',
        pluginSameNameError: 'There is already a plugin with this name.',
        templateNameMissingError: 'Please enter a template name.'
      }
    }
  });
<|endoftext|>


<commit_before>$(document).ready(function () {

    var $modals = $('.modal');
    var $editModal = $('.edit-modal');
    var customFieldCount = 0;

    function guidGenerator() {
        var S4 = function () {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        };
        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }

    var deleteCustomField = function (customFieldId) {
        $('#' + customFieldId).remove();
    };

    var addNewCustomField = function (modal) {
        var $customFields = modal.find('.custom-fields');
        var $newCustomFieldKey = modal.find('.new-custom-field-key');
        var $newCustomFieldValue = modal.find('.new-custom-field-value');
        populateCustomField($customFields, {
            key: $newCustomFieldKey.val(),
            value: $newCustomFieldValue.val()
        });
        $newCustomFieldKey.val("");
        $newCustomFieldValue.val("");
    };

    var populateCustomField = function ($customFields, field) {
        var _id = guidGenerator();
        var $field = $("
Key: " + field.key + ", Value:" + field.value + "
")
            .append($("<input name='customs[" + customFieldCount + "][key]' value='" + field.key + "' type='hidden'></input>"))
            .append($("<input name='customs[" + customFieldCount + "][value]' value='" + field.value + "' type='hidden'></input>"))
            .append($("")
                .click(deleteCustomField.bind(this, _id))
            );
        $customFields.append($field);
        customFieldCount++;
    };

    var populateCustomFields = function (modal, customFields) {
        var $customFields = modal.find('.custom-fields');
        customFields.forEach(function (field) {
            populateCustomField($customFields, field);
        });
        modal.find('.new-custom-field-add').click(addNewCustomField.bind(this, modal));
    };

    var populateCourseSelection = function (modal, courses) {
        var $selection = modal.find('.course-selection');
        courses.forEach(function (course) {
            var option = document.createElement("option");
            option.text = course.name;
            option.value = course._id;
            $selection.append(option);
        });
        $selection.chosen().trigger("chosen:updated");
    };

    var populateModalForm = function (modal, data) {

        var $title = modal.find('.modal-title');
        var $btnSubmit = modal.find('.btn-submit');
        var $btnClose = modal.find('.btn-close');
        var $form = modal.find('.modal-form');

        $title.html(data.title);
        $btnSubmit.html(data.submitLabel);
        $btnClose.html(data.closeLabel);

        // fields
        $('[name]', $form).not('[data-force-value]').each(function () {
            var value = (data.fields || {})[$(this).prop('name').replace('[]', '')] || '';
            switch ($(this).prop("type")) {
                case "radio":
                case "checkbox":
                    $(this).each(function () {
                        if ($(this).attr('value') == value) $(this).attr("checked", value);
                    });
                    break;
                default:
                    $(this).val(value).trigger("chosen:updated");
            }
        });
    };

    $('.template_tool').on('click', function (e) {
        e.preventDefault();
        var entry = $(this).attr('href');
        $.getJSON(entry, function (result) {
            populateModalForm($editModal, {
                title: 'Bearbeiten',
                closeLabel: 'Schließen',
                submitLabel: 'Speichern',
                fields: result.tool
            });
            populateCourseSelection($editModal, result.courses.data);
            populateCustomFields($editModal, result.tool.customs);
            $editModal.modal('show');
        });
    });

    $modals.find('.close, .btn-close').on('click', function () {
        $modals.modal('hide');
    });

});<commit_msg>fix a bug that does not remove old custom params from modal (#162)<commit_after>$(document).ready(function () {

    var $modals = $('.modal');
    var $editModal = $('.edit-modal');
    var customFieldCount = 0;

    function guidGenerator() {
        var S4 = function () {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        };
        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }

    var deleteCustomField = function (customFieldId) {
        $('#' + customFieldId).remove();
    };

    var addNewCustomField = function (modal) {
        var $customFields = modal.find('.custom-fields');
        var $newCustomFieldKey = modal.find('.new-custom-field-key');
        var $newCustomFieldValue = modal.find('.new-custom-field-value');
        populateCustomField($customFields, {
            key: $newCustomFieldKey.val(),
            value: $newCustomFieldValue.val()
        });
        $newCustomFieldKey.val("");
        $newCustomFieldValue.val("");
    };

    var populateCustomField = function ($customFields, field) {
        if (!field.key || field.key == '') return;

        var _id = guidGenerator();
        var $field = $("
Key: " + field.key + ", Value: " + field.value + "
")
            .append($("<input name='customs[" + customFieldCount + "][key]' value='" + field.key + "' type='hidden'></input>"))
            .append($("<input name='customs[" + customFieldCount + "][value]' value='" + field.value + "' type='hidden'></input>"))
            .append($("")
                .click(deleteCustomField.bind(this, _id))
            );
        $customFields.append($field);
        customFieldCount++;
    };

    var populateCustomFields = function (modal, customFields) {
        var $customFields = modal.find('.custom-fields');

        // cleanup
        $customFields.empty();

        customFields.forEach(function (field) {
            populateCustomField($customFields, field);
        });
        modal.find('.new-custom-field-add').click(addNewCustomField.bind(this, modal));
    };

    var populateCourseSelection = function (modal, courses) {
        var $selection = modal.find('.course-selection');
        courses.forEach(function (course) {
            var option = document.createElement("option");
            option.text = course.name;
            option.value = course._id;
            $selection.append(option);
        });
        $selection.chosen().trigger("chosen:updated");
    };

    var populateModalForm = function (modal, data) {

        var $title = modal.find('.modal-title');
        var $btnSubmit = modal.find('.btn-submit');
        var $btnClose = modal.find('.btn-close');
        var $form = modal.find('.modal-form');

        $title.html(data.title);
        $btnSubmit.html(data.submitLabel);
        $btnClose.html(data.closeLabel);

        // fields
        $('[name]', $form).not('[data-force-value]').each(function () {
            var value = (data.fields || {})[$(this).prop('name').replace('[]', '')] || '';
            switch ($(this).prop("type")) {
                case "radio":
                case "checkbox":
                    $(this).each(function () {
                        if ($(this).attr('value') == value) $(this).attr("checked", value);
                    });
                    break;
                default:
                    $(this).val(value).trigger("chosen:updated");
            }
        });
    };

    $('.template_tool').on('click', function (e) {
        e.preventDefault();
        var entry = $(this).attr('href');
        $.getJSON(entry, function (result) {
            populateModalForm($editModal, {
                title: 'Bearbeiten',
                closeLabel: 'Schließen',
                submitLabel: 'Speichern',
                fields: result.tool
            });
            populateCourseSelection($editModal, result.courses.data);
            populateCustomFields($editModal, result.tool.customs);
            $editModal.modal('show');
        });
    });

    $modals.find('.close, .btn-close').on('click', function () {
        $modals.modal('hide');
    });

});<|endoftext|>