<commit_before>/*global $:false, jQuery:false, window:false, document:false */

$.prototype.iconify = function (icon) {
    'use strict';
    var $icon = $("").addClass(icon).css('float', 'left');
    $(this).css('width', "16px").prepend($icon);
};

var eventize = function (that) {
    'use strict';
    var events = {};
    that.on = function (tag, callback) {
        if (events[tag] === undefined) {
            events[tag] = [];
        }
        events[tag].push(callback);
        return that;
    };
    that.fire = function (tag, e) {
        var i;
        if (events[tag] !== undefined) {
            for (i = 0; i < events[tag].length; i += 1) {
                events[tag][i].apply(that, [e]);
            }
        }
        return that;
    };
    return that;
};

var SaveButton = {
    /*
        options: {
            save: "Function to call when the user clicks Save",
            unsavedMessage: "Message to display when there are unsaved changes and the user leaves the page"
        }
    */
    init: function (options) {
        var button = {
            disabled: false,
            $save: $('').text(SaveButton.message.SAVE).click(function () {
                button.fire('save');
            }).addClass('btn btn-success'),
            $retry: $('').text(SaveButton.message.RETRY).click(function () {
                button.fire('save');
            }).addClass('btn btn-success'),
            $saving: $('').text(SaveButton.message.SAVING).prepend(' ').addClass('btn disabled'),
            $saved: $('').text(SaveButton.message.SAVED).addClass('btn disabled'),
            ui: $('
').addClass('pull-right'),
            setStateWhenReady: function (state) {
                if (this.state === 'saving') {
                    this.nextState = state;
                } else {
                    this.setState(state);
                }
            },
            setState: function (state) {
                if (this.state === state) {
                    return;
                }
                this.state = state;
                this.$save.detach();
                this.$saving.detach();
                this.$saved.detach();
                this.$retry.detach();
                if (state === 'save') {
                    this.ui.append(this.$save);
                } else if (state === 'saving') {
                    this.ui.append(this.$saving);
                } else if (state === 'saved') {
                    this.ui.append(this.$saved);
                } else if (state === 'retry') {
                    this.ui.append(this.$retry);
                }
                this.fire('state:change');
            },
            ajaxOptions: function (options) {
                var options = options || {},
                    beforeSend = options.beforeSend || function () {},
                    success = options.success || function () {},
                    error = options.error || function () {},
                    that = this;
                options.beforeSend = function () {
                    that.setState('saving');
                    that.nextState = 'saved';
                    beforeSend.apply(this, arguments);
                };
                options.success = function (data) {
                    that.setState(that.nextState);
                    success.apply(this, arguments);
                };
                options.error = function (data) {
                    that.nextState = null;
                    that.setState('retry');
                    responseText = data.responseText || '';
                    alert(SaveButton.message.ERROR_SAVING + '\n' +  data.responseText);
                    error.apply(this, arguments);
                };
                return options;
            },
            ajax: function (options) {
                var jqXHR = $.ajax(button.ajaxOptions(options));
                if (!jqXHR) {
                    // request was aborted
                    this.setState('save');
                }
            }
        };
        eventize(button);
        button.setState('saved');
        button.on('change', function () {
            this.setStateWhenReady('save');
        });
        button.on('disable', function () {
            this.disabled = true;
            this.$save.addClass('disabled');
            this.$saving.addClass('disabled');
            this.$retry.addClass('disabled');
        });
        button.on('enable', function () {
            this.disabled = false;
            this.$save.removeClass('disabled');
            this.$saving.removeClass('disabled');
            this.$retry.removeClass('disabled');
        });
        button.on('save', function () {
            if (button.disabled){
                return;
            } else if (options.save) {
                options.save();
            } else if (options.saveRequest){
                var o = button.ajaxOptions();
                o.beforeSend();
                options.saveRequest()
                    .success(o.success)
                    .error(o.error)
                ;
            }
        });

        var beforeunload = function () {
            var parentEl = button.ui.parents()[button.ui.parents().length - 1];
            var stillAttached = parentEl ? parentEl.tagName.toLowerCase() == 'html' : false;
            if (button.state !== 'saved' && stillAttached) {
                return options.unsavedMessage || "";
            }
        };
        COMMCAREHQ.bindBeforeUnload(beforeunload);
        return button;
    },
    initForm: function ($form, options) {
        var url = $form.attr('action'),
            button = SaveButton.init({
                unsavedMessage: options.unsavedMessage,
                save: function () {
                    button.ajax({
                        url: url,
                        type: 'POST',
                        dataType: 'json',
                        data: $form.serialize(),
                        success: options.success
                    });
                }
            }),
            fireChange = function () {
                button.fire('change');
            };
        $form.find('*').change(fireChange);
//        $form.on('textchange', 'input, textarea', fireChange);
        $form.find('input, textarea').bind('textchange', fireChange);
        return button;
    },
    message: {
        SAVE: 'Save',
        SAVING: 'Saving',
        SAVED: 'Saved',
        RETRY: 'Try Again',
        ERROR_SAVING: 'There was an error saving'
    }
};

var COMMCAREHQ = (function () {
    'use strict';
    return {
        icons: {
            GRIP:   'fa fa-sort icon-resize-vertical icon-blue',
            ADD:    'icon-plus icon-blue',
            COPY:   'icon-copy icon-blue',
            DELETE: 'fa fa-remove icon-remove icon-blue',
            PAPERCLIP: 'icon-paper-clip'
        },
        makeHqHelp: function (opts, wrap) {
            wrap = wrap === undefined ? true : wrap;
            var iconClass = "icon-question-sign";
            if (opts.bootstrap3){
                iconClass = "fa fa-question-circle";
            }
            var el = $(
                '
' +
                    '' +
                        '
'
                ),
                attrs = ['content', 'title', 'placement'];
            attrs.map(function (attr) {
                el.find('a').attr("data-"+attr, opts[attr]);
            });
            if (wrap) {
                el.hqHelp();
            }
            return el;
        },
        transformHelpTemplate: function ($template, wrap) {
            var $help = COMMCAREHQ.makeHqHelp($template.data(), wrap);
            $help.insertAfter($template);
            $template.remove();
        },
        initBlock: function ($elem) {
            $('.submit_on_click', $elem).on("click", function (e) {
                e.preventDefault();
                if (!$(this).data('clicked')) {
                    $(this).prev('form').submit();
                    $(this).data('clicked', 'true').children('i').removeClass().addClass("icon-refresh icon-spin");
                }
            });

            $('.submit').click(function (e) {
                var $form = $(this).closest('.form, form'),
                    data = $form.my_serialize(),
                    action = $form.attr('action') || $form.data('action');

                e.preventDefault();
                $.postGo(action, $.unparam(data));
            });
            $('.post-link').click(function (e) {
                e.preventDefault();
                $.postGo($(this).attr('href'), {});
            });

            // trick to give a select menu an initial value
            $('select[data-value]', $elem).each(function () {
                var val = $(this).attr('data-value');
                if (val) {
                    $(this).find('option').removeAttr('selected');
                    $(this).find('option[value="' + val + '"]').attr('selected', 'true');
                }
            });

            $(".button", $elem).button().wrap('');
            $("input[type='submit']", $elem).button();
            $("input[type='text'], input[type='password'], textarea", $elem);
            $('.container', $elem).addClass('ui-widget ui-widget-content');
            $('.config', $elem).wrap('
').parent().addClass('container block ui-corner-all');

            $('.confirm-submit', $elem).click(function () {
                var $form = $(this).closest('form'),
                    message = $form.data('message') || function () {
                        $(this).append($form.find('.dialog-message').html());
                    },
                    title = $form.data('title');
                COMMCAREHQ.confirm({
                    title: title,
                    message: message,
                    ok: function () {
                        $form.submit();
                    }
                });
                return false;
            });
        },
        updateDOM: function (update) {
            var key;
            for (key in update) {
                if (update.hasOwnProperty(key)) {
                    $(key).text(update[key]).val(update[key]);
                }
            }
        },
        confirm: function (options) {
            var title = options.title,
                message = options.message || "",
                onOpen = options.open || function () {},
                onOk = options.ok,
                $dialog = $('
');

            if (typeof message === "function") {
                message.apply($dialog);
            } else if (message) {
                $dialog.text(message);
            }
            $dialog.dialog({
                title: title,
                modal: true,
                resizable: false,
                open: function () {
                    onOpen.apply($dialog);
                },
                buttons: [{
                    text: "Cancel",
                    click: function () {
                        $(this).dialog('close');
                    }
                }, {
                    text: "OK",
                    click: function () {
                        $(this).dialog('close');
                        onOk.apply($dialog);
                    }
                }]
            });
        },
        SaveButton: SaveButton,
        beforeUnload: [],
        bindBeforeUnload: function (callback) {
            COMMCAREHQ.beforeUnload.push(callback);
        },
        beforeUnloadCallback: function () {
            for (var i = 0; i < COMMCAREHQ.beforeUnload.length; i++) {
                var message = COMMCAREHQ.beforeUnload[i]();
                if (message !== null && message !== undefined) {
                    return message;
                }
            }
        }
    };
}());

$(function () {
    'use strict';
    $('.delete_link').iconify('icon-remove');
    $(".delete_link").addClass("dialog_opener");
    $(".delete_dialog").addClass("dialog");
    $('.new_link').iconify('icon-plus');
    $('.edit_link').iconify('icon-pencil');

    $(".message").addClass('ui-state-highlight ui-corner-all').addClass("shadow");

    COMMCAREHQ.initBlock($("body"));

    $(window).bind('beforeunload', COMMCAREHQ.beforeUnloadCallback);

});
<commit_msg>update icons in main.js for bootstrap 3<commit_after>/*global $:false, jQuery:false, window:false, document:false */

$.prototype.iconify = function (icon) {
    'use strict';
    var $icon = $("").addClass(icon).css('float', 'left');
    $(this).css('width', "16px").prepend($icon);
};

var eventize = function (that) {
    'use strict';
    var events = {};
    that.on = function (tag, callback) {
        if (events[tag] === undefined) {
            events[tag] = [];
        }
        events[tag].push(callback);
        return that;
    };
    that.fire = function (tag, e) {
        var i;
        if (events[tag] !== undefined) {
            for (i = 0; i < events[tag].length; i += 1) {
                events[tag][i].apply(that, [e]);
            }
        }
        return that;
    };
    return that;
};

var SaveButton = {
    /*
        options: {
            save: "Function to call when the user clicks Save",
            unsavedMessage: "Message to display when there are unsaved changes and the user leaves the page"
        }
    */
    init: function (options) {
        var button = {
            disabled: false,
            $save: $('').text(SaveButton.message.SAVE).click(function () {
                button.fire('save');
            }).addClass('btn btn-success'),
            $retry: $('').text(SaveButton.message.RETRY).click(function () {
                button.fire('save');
            }).addClass('btn btn-success'),
            $saving: $('').text(SaveButton.message.SAVING).prepend(' ').addClass('btn disabled'),
            $saved: $('').text(SaveButton.message.SAVED).addClass('btn disabled'),
            ui: $('
').addClass('pull-right'),
            setStateWhenReady: function (state) {
                if (this.state === 'saving') {
                    this.nextState = state;
                } else {
                    this.setState(state);
                }
            },
            setState: function (state) {
                if (this.state === state) {
                    return;
                }
                this.state = state;
                this.$save.detach();
                this.$saving.detach();
                this.$saved.detach();
                this.$retry.detach();
                if (state === 'save') {
                    this.ui.append(this.$save);
                } else if (state === 'saving') {
                    this.ui.append(this.$saving);
                } else if (state === 'saved') {
                    this.ui.append(this.$saved);
                } else if (state === 'retry') {
                    this.ui.append(this.$retry);
                }
                this.fire('state:change');
            },
            ajaxOptions: function (options) {
                var options = options || {},
                    beforeSend = options.beforeSend || function () {},
                    success = options.success || function () {},
                    error = options.error || function () {},
                    that = this;
                options.beforeSend = function () {
                    that.setState('saving');
                    that.nextState = 'saved';
                    beforeSend.apply(this, arguments);
                };
                options.success = function (data) {
                    that.setState(that.nextState);
                    success.apply(this, arguments);
                };
                options.error = function (data) {
                    that.nextState = null;
                    that.setState('retry');
                    responseText = data.responseText || '';
                    alert(SaveButton.message.ERROR_SAVING + '\n' +  data.responseText);
                    error.apply(this, arguments);
                };
                return options;
            },
            ajax: function (options) {
                var jqXHR = $.ajax(button.ajaxOptions(options));
                if (!jqXHR) {
                    // request was aborted
                    this.setState('save');
                }
            }
        };
        eventize(button);
        button.setState('saved');
        button.on('change', function () {
            this.setStateWhenReady('save');
        });
        button.on('disable', function () {
            this.disabled = true;
            this.$save.addClass('disabled');
            this.$saving.addClass('disabled');
            this.$retry.addClass('disabled');
        });
        button.on('enable', function () {
            this.disabled = false;
            this.$save.removeClass('disabled');
            this.$saving.removeClass('disabled');
            this.$retry.removeClass('disabled');
        });
        button.on('save', function () {
            if (button.disabled){
                return;
            } else if (options.save) {
                options.save();
            } else if (options.saveRequest){
                var o = button.ajaxOptions();
                o.beforeSend();
                options.saveRequest()
                    .success(o.success)
                    .error(o.error)
                ;
            }
        });

        var beforeunload = function () {
            var parentEl = button.ui.parents()[button.ui.parents().length - 1];
            var stillAttached = parentEl ? parentEl.tagName.toLowerCase() == 'html' : false;
            if (button.state !== 'saved' && stillAttached) {
                return options.unsavedMessage || "";
            }
        };
        COMMCAREHQ.bindBeforeUnload(beforeunload);
        return button;
    },
    initForm: function ($form, options) {
        var url = $form.attr('action'),
            button = SaveButton.init({
                unsavedMessage: options.unsavedMessage,
                save: function () {
                    button.ajax({
                        url: url,
                        type: 'POST',
                        dataType: 'json',
                        data: $form.serialize(),
                        success: options.success
                    });
                }
            }),
            fireChange = function () {
                button.fire('change');
            };
        $form.find('*').change(fireChange);
//        $form.on('textchange', 'input, textarea', fireChange);
        $form.find('input, textarea').bind('textchange', fireChange);
        return button;
    },
    message: {
        SAVE: 'Save',
        SAVING: 'Saving',
        SAVED: 'Saved',
        RETRY: 'Try Again',
        ERROR_SAVING: 'There was an error saving'
    }
};

var COMMCAREHQ = (function () {
    'use strict';
    return {
        icons: {
            GRIP:   'fa fa-sort icon-resize-vertical icon-blue',
            ADD:    'fa fa-plus icon-plus icon-blue',
            COPY:   'fa fa-copy icon-copy icon-blue',
            DELETE: 'fa fa-remove icon-remove icon-blue',
            PAPERCLIP: 'fa fa-paperclip icon-paper-clip'
        },
        makeHqHelp: function (opts, wrap) {
            wrap = wrap === undefined ? true : wrap;
            var iconClass = "icon-question-sign";
            if (opts.bootstrap3){
                iconClass = "fa fa-question-circle";
            }
            var el = $(
                '
' +
                    '' +
                        '
'
                ),
                attrs = ['content', 'title', 'placement'];
            attrs.map(function (attr) {
                el.find('a').attr("data-"+attr, opts[attr]);
            });
            if (wrap) {
                el.hqHelp();
            }
            return el;
        },
        transformHelpTemplate: function ($template, wrap) {
            var $help = COMMCAREHQ.makeHqHelp($template.data(), wrap);
            $help.insertAfter($template);
            $template.remove();
        },
        initBlock: function ($elem) {
            $('.submit_on_click', $elem).on("click", function (e) {
                e.preventDefault();
                if (!$(this).data('clicked')) {
                    $(this).prev('form').submit();
                    $(this).data('clicked', 'true').children('i').removeClass().addClass("fa fa-refresh fa-spin icon-refresh icon-spin");
                }
            });

            $('.submit').click(function (e) {
                var $form = $(this).closest('.form, form'),
                    data = $form.my_serialize(),
                    action = $form.attr('action') || $form.data('action');

                e.preventDefault();
                $.postGo(action, $.unparam(data));
            });
            $('.post-link').click(function (e) {
                e.preventDefault();
                $.postGo($(this).attr('href'), {});
            });

            // trick to give a select menu an initial value
            $('select[data-value]', $elem).each(function () {
                var val = $(this).attr('data-value');
                if (val) {
                    $(this).find('option').removeAttr('selected');
                    $(this).find('option[value="' + val + '"]').attr('selected', 'true');
                }
            });

            $(".button", $elem).button().wrap('');
            $("input[type='submit']", $elem).button();
            $("input[type='text'], input[type='password'], textarea", $elem);
            $('.container', $elem).addClass('ui-widget ui-widget-content');
            $('.config', $elem).wrap('
').parent().addClass('container block ui-corner-all');

            $('.confirm-submit', $elem).click(function () {
                var $form = $(this).closest('form'),
                    message = $form.data('message') || function () {
                        $(this).append($form.find('.dialog-message').html());
                    },
                    title = $form.data('title');
                COMMCAREHQ.confirm({
                    title: title,
                    message: message,
                    ok: function () {
                        $form.submit();
                    }
                });
                return false;
            });
        },
        updateDOM: function (update) {
            var key;
            for (key in update) {
                if (update.hasOwnProperty(key)) {
                    $(key).text(update[key]).val(update[key]);
                }
            }
        },
        confirm: function (options) {
            var title = options.title,
                message = options.message || "",
                onOpen = options.open || function () {},
                onOk = options.ok,
                $dialog = $('
');

            if (typeof message === "function") {
                message.apply($dialog);
            } else if (message) {
                $dialog.text(message);
            }
            $dialog.dialog({
                title: title,
                modal: true,
                resizable: false,
                open: function () {
                    onOpen.apply($dialog);
                },
                buttons: [{
                    text: "Cancel",
                    click: function () {
                        $(this).dialog('close');
                    }
                }, {
                    text: "OK",
                    click: function () {
                        $(this).dialog('close');
                        onOk.apply($dialog);
                    }
                }]
            });
        },
        SaveButton: SaveButton,
        beforeUnload: [],
        bindBeforeUnload: function (callback) {
            COMMCAREHQ.beforeUnload.push(callback);
        },
        beforeUnloadCallback: function () {
            for (var i = 0; i < COMMCAREHQ.beforeUnload.length; i++) {
                var message = COMMCAREHQ.beforeUnload[i]();
                if (message !== null && message !== undefined) {
                    return message;
                }
            }
        }
    };
}());

$(function () {
    'use strict';
    $('.delete_link').iconify('fa fa-remove icon-remove');
    $(".delete_link").addClass("dialog_opener");
    $(".delete_dialog").addClass("dialog");
    $('.new_link').iconify('fa fa-plus icon-plus');
    $('.edit_link').iconify('fa fa-pencil icon-pencil');

    $(".message").addClass('ui-state-highlight ui-corner-all').addClass("shadow");

    COMMCAREHQ.initBlock($("body"));

    $(window).bind('beforeunload', COMMCAREHQ.beforeUnloadCallback);

});
<|endoftext|>


<commit_before>/*
 * patternlab-node - v0.10.1 - 2015
 *
 * Geoffrey Pursell, Brian Muenzenmeyer, and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

'use strict';

var path = require('path');
var diveSync = require('diveSync');
var engineMatcher = /^engine_(.*)\.js/;
var enginesDirectory = __dirname;

var PatternEngines; // the main export object
var engineNameForExtension; // generated mapping of extension to engine name

// free "private" functions, for internal setup only

function findSupportedPatternEngineNames() {
  var foundPatternEngineNames = [];

  // find
  diveSync(enginesDirectory, {
    recursive: false,
    filter: function (filePath, dir) {
      var baseName = path.basename(filePath),
        engineMatch = baseName.match(engineMatcher);

      if (dir || engineMatch !== null) { return true; }
      return false;
    }
  }, function (err, filePath) {
    if (err) { throw err; }
    var baseName = path.basename(filePath),
      engineMatch = baseName.match(engineMatcher),
      foundEngineName = engineMatch[1];

    foundPatternEngineNames.push(foundEngineName);
  });

  return foundPatternEngineNames;
}

// try to load all supported engines
function loadAllEngines(enginesObject) {
  console.log('\nLoading engines...');

  enginesObject.supportedPatternEngineNames.forEach(function (engineName) {
    var notLoaded = false;

    try {
      enginesObject[engineName] = require('./engine_' + engineName);
    } catch (err) {
      // Handle errors loading each pattern engine. This will usually be
      // because the engine's renderer hasn't been installed by the end user
      // -- we don't include any of them (except mustache) by default as
      // depedencies in package.json.
      notLoaded = (err.code === 'MODULE_NOT_FOUND');
    } finally {
      console.log('-', engineName, 'engine:',
                  notLoaded ? 'renderer not installed; engine disabled' : 'good to go');
    }
  });
  console.log('...done loading engines.\n');
}

// produce a mapping between file extension and engine name for each of the
// loaded engines
function createFileExtensionToEngineNameMap(enginesObject) {
  var mapping = {};

  Object.keys(enginesObject).forEach(function (engineName) {
    var extensionForEngine = enginesObject[engineName].engineFileExtension;
    mapping[extensionForEngine] = engineName;
  });

  return mapping;
}

//
// PatternEngines: the main export of this module
//
// It's an Object/hash of all loaded pattern engines, empty at first.  My
// intention here is to make this return an object that can be used to obtain
// any loaded PatternEngine by addressing them like this:
//
//   var PatternEngines = require('./pattern_engines/pattern_engines');
//   var Mustache = PatternEngines['mustache'];
//
// Object.create lets us create an object with a specified prototype. We want
// this here because we would like the object's "own properties" to include
// only the engine names so we can easily iterate over them; all the handy
// methods and properites below should therefore be on its prototype.

PatternEngines = Object.create({
  // build the list of supported pattern engines based on what plugins we have
  // in the pattern_engines directory
  supportedPatternEngineNames: findSupportedPatternEngineNames(),

  getEngineNameForPattern: function (pattern) {
    // avoid circular dependency by putting this in here. TODO: is this slow?
    var of = require('../object_factory');

    if (pattern instanceof of.oPattern && typeof pattern.fileExtension === 'string' && pattern.fileExtension) {
      return engineNameForExtension[pattern.fileExtension];
    }

    // otherwise, assume it's a plain mustache template string and act
    // accordingly
    return 'mustache';
  },

  getEngineForPattern: function (pattern) {
    if (pattern.isPseudoPattern) {
      return this.getEngineForPattern(pattern.basePattern);
    } else {
      var engineName = this.getEngineNameForPattern(pattern);
      return this[engineName];
    }
  },

  getSupportedFileExtensions: function () {
    var engineNames = Object.keys(PatternEngines);
    return engineNames.map(function (engineName) {
      return PatternEngines[engineName].engineFileExtension;
    });
  },

  isFileExtensionSupported: function (fileExtension) {
    var supportedExtensions = PatternEngines.getSupportedFileExtensions();
    return (supportedExtensions.lastIndexOf(fileExtension) !== -1);
  },

  // given a filename, return a boolean: whether or not the filename indicates
  // that the file is pseudopattern JSON
  isPseudoPatternJSON: function (filename) {
    var extension = path.extname(filename);
    return (extension === '.json' && filename.indexOf('~') > -1);
  },

  // takes a filename string, not a full path; a basename (plus extension)
  // ignore _underscored patterns, dotfiles, and anything not recognized by a
  // loaded pattern engine. Pseudo-pattern .json files ARE considered to be
  // pattern files!
  isPatternFile: function (filename) {
    // skip hidden patterns/files without a second thought
    var extension = path.extname(filename);
    if (filename.charAt(0) === '.' ||
        (extension === '.json' && !PatternEngines.isPseudoPatternJSON(filename))) {
      return false;
    }

    // not a hidden pattern, let's dig deeper
    var supportedPatternFileExtensions = PatternEngines.getSupportedFileExtensions();
    return (supportedPatternFileExtensions.lastIndexOf(extension) !== -1 ||
            PatternEngines.isPseudoPatternJSON(filename));
  }
});

// load up the engines we found
loadAllEngines(PatternEngines);

// mapping of file extensions to engine names, for lookup use
engineNameForExtension = createFileExtensionToEngineNameMap(PatternEngines);

module.exports = PatternEngines;
<commit_msg>engine loader now finds the mustache engine module from the edition!<commit_after>/*
 * patternlab-node - v0.10.1 - 2015
 *
 * Geoffrey Pursell, Brian Muenzenmeyer, and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

'use strict';

var path = require('path');
var diveSync = require('diveSync');
var engineMatcher = /^patternengine-node-(.*)$/;
var enginesDirectory = path.join(process.cwd(), 'node_modules');
var PatternEngines; // the main export object
var engineNameForExtension; // generated mapping of extension to engine name

// free "private" functions, for internal setup only

// given a path: return the engine name is the path points to a valid engine
// module directory, or false if it doesn't
function isEngineModule(filePath) {
  var baseName = path.basename(filePath);
  var engineMatch = baseName.match(engineMatcher);

  if (engineMatch) { return engineMatch[1]; }
  return false;
}

function getEngineModulePath(engineName) {
  return path.resolve(enginesDirectory, "patternengine-node-" + engineName);
}

// go find the names of all found engines
function findSupportedPatternEngineNames() {
  var foundPatternEngineNames = [];

  // iterate over module directory and build a list of available pattern engine
  // names
  diveSync(enginesDirectory, {
    recursive: false,
    directories: true
  }, function (err, filePath) {
    if (err) { throw err; }
    var foundEngineName = isEngineModule(filePath);
    if (foundEngineName) {
      foundPatternEngineNames.push(foundEngineName);
    }
  });

  return foundPatternEngineNames;
}

// try to load all supported engines
function loadAllEngines(enginesObject) {
  console.log('\nLoading engines...');

  enginesObject.supportedPatternEngineNames.forEach(function (engineName) {
    var notLoaded = false;

    try {
      enginesObject[engineName] = require(getEngineModulePath(engineName));
    } catch (err) {
      // Handle errors loading each pattern engine. This will usually be
      // because the engine's renderer hasn't been installed by the end user
      // -- we don't include any of them (except mustache) by default as
      // depedencies in package.json.
      notLoaded = (err.code === 'MODULE_NOT_FOUND');
    } finally {
      console.log('-', engineName, 'engine:',
                  notLoaded ? 'renderer not installed; engine disabled' : 'good to go');
    }
  });
  console.log('...done loading engines.\n');
}

// produce a mapping between file extension and engine name for each of the
// loaded engines
function createFileExtensionToEngineNameMap(enginesObject) {
  var mapping = {};

  Object.keys(enginesObject).forEach(function (engineName) {
    var extensionForEngine = enginesObject[engineName].engineFileExtension;
    mapping[extensionForEngine] = engineName;
  });

  return mapping;
}

//
// PatternEngines: the main export of this module
//
// It's an Object/hash of all loaded pattern engines, empty at first.  My
// intention here is to make this return an object that can be used to obtain
// any loaded PatternEngine by addressing them like this:
//
//   var PatternEngines = require('./pattern_engines/pattern_engines');
//   var Mustache = PatternEngines['mustache'];
//
// Object.create lets us create an object with a specified prototype. We want
// this here because we would like the object's "own properties" to include
// only the engine names so we can easily iterate over them; all the handy
// methods and properites below should therefore be on its prototype.

PatternEngines = Object.create({
  // build the list of supported pattern engines based on what plugins we have
  // in the pattern_engines directory
  supportedPatternEngineNames: findSupportedPatternEngineNames(),

  getEngineNameForPattern: function (pattern) {
    // avoid circular dependency by putting this in here. TODO: is this slow?
    var of = require('../object_factory');

    if (pattern instanceof of.oPattern && typeof pattern.fileExtension === 'string' && pattern.fileExtension) {
      return engineNameForExtension[pattern.fileExtension];
    }

    // otherwise, assume it's a plain mustache template string and act
    // accordingly
    return 'mustache';
  },

  getEngineForPattern: function (pattern) {
    if (pattern.isPseudoPattern) {
      return this.getEngineForPattern(pattern.basePattern);
    } else {
      var engineName = this.getEngineNameForPattern(pattern);
      return this[engineName];
    }
  },

  getSupportedFileExtensions: function () {
    var engineNames = Object.keys(PatternEngines);
    return engineNames.map(function (engineName) {
      return PatternEngines[engineName].engineFileExtension;
    });
  },

  isFileExtensionSupported: function (fileExtension) {
    var supportedExtensions = PatternEngines.getSupportedFileExtensions();
    return (supportedExtensions.lastIndexOf(fileExtension) !== -1);
  },

  // given a filename, return a boolean: whether or not the filename indicates
  // that the file is pseudopattern JSON
  isPseudoPatternJSON: function (filename) {
    var extension = path.extname(filename);
    return (extension === '.json' && filename.indexOf('~') > -1);
  },

  // takes a filename string, not a full path; a basename (plus extension)
  // ignore _underscored patterns, dotfiles, and anything not recognized by a
  // loaded pattern engine. Pseudo-pattern .json files ARE considered to be
  // pattern files!
  isPatternFile: function (filename) {
    // skip hidden patterns/files without a second thought
    var extension = path.extname(filename);
    if (filename.charAt(0) === '.' ||
        (extension === '.json' && !PatternEngines.isPseudoPatternJSON(filename))) {
      return false;
    }

    // not a hidden pattern, let's dig deeper
    var supportedPatternFileExtensions = PatternEngines.getSupportedFileExtensions();
    return (supportedPatternFileExtensions.lastIndexOf(extension) !== -1 ||
            PatternEngines.isPseudoPatternJSON(filename));
  }
});

// load up the engines we found
loadAllEngines(PatternEngines);

// mapping of file extensions to engine names, for lookup use
engineNameForExtension = createFileExtensionToEngineNameMap(PatternEngines);

module.exports = PatternEngines;
<|endoftext|>


<commit_before>module('lively.ide.codeeditor.modes.Clojure').requires('lively.ide.codeeditor.ace').toRun(function() {

lively.ide.codeeditor.modes.Clojure.ReplServer = {};

Object.extend(lively.ide.codeeditor.modes.Clojure.ReplServer, {

    livelyLeinProfile: "{:plugins [[lein-pprint \"1.1.1\"]]\n"
                     + " :dependencies [[rksm/repl.utils \"0.1.1\"]\n"
                     + "                ;; for vinyasa lein\n"
                     + "                [leiningen #=(leiningen.core.main/leiningen-version)]\n"
                     + "                ;; trace execution\n"
                     + "                [org.clojure/tools.trace \"0.7.8\"]\n"
                     + "                ;; install dependencies / packages without restart\n"
                     + "                [com.cemerick/pomegranate \"0.3.0\"]\n"
                     + "                ;; cljs repl ++\n"
                     + "                [com.cemerick/piggieback \"0.1.4-SNAPSHOT\"]\n"
                     + "                ;; \"quick and dirty debugging\n"
                     + "                [spyscope \"0.1.4\"]\n"
                     + "                ;; reload namespaces, recursively tracking dependencies\n"
                     + "                [org.clojure/tools.namespace \"0.2.4\"]\n"
                     + "                ;; java reflection\n"
                     + "                [im.chit/iroh \"0.1.11\"]\n"
                     + "                ;; pretty stacktraces\n"
                     + "                [io.aviso/pretty \"0.1.8\"]\n"
                     + "                ;; inject stuff in namespace + other goodies\n"
                     + "                ;; see http://z.caudate.me/give-your-clojure-workflow-more-flow/\n"
                     + "                [im.chit/vinyasa \"0.2.2\"]]\n"
                     + " :injections [(require 'spyscope.core)\n"
                     + "              (require 'vinyasa.inject)\n"
                     + "              (require 'iroh.core)\n"
                     + "              (vinyasa.inject/in\n"
                     + "              clojure.core\n"
                     + "              [rksm.repl.utils lein search-for-symbol get-stack print-stack dumb-stack traced-fn]\n"
                     + "              [vinyasa.pull [pull pull]]\n"
                     + "              [clojure.java.shell sh]\n"
                     + "              [clojure.repl apropos dir doc find-doc source [root-cause cause]]\n"
                     + "              [clojure.tools.namespace.repl [refresh refresh]]\n"
                     + "              [clojure.pprint [pprint >pprint]]\n"
                     + "              [iroh.core .% .%> .*]\n"
                     + "              [clojure.tools.trace dotrace trace-ns untrace-ns])]}\n",

    ensure: function(options, thenDo) {
        if (!thenDo) { thenDo = options; options = {}; }
        var cmd = this.getCurrentServerCommand();
        if (cmd) {
            Functions.waitFor(5000, function() {
                return cmd.getStdout().include("nREPL server started");
            }, function(err) { thenDo(null, cmd); });
        } else this.start(options, thenDo);
    },

    getCurrentServerCommand: function() {
        var cmdQueueName = "lively.clojure.replServer";
        var q = lively.shell.commandQueue[cmdQueueName];
        var cmd = q && q[0];
        return cmd && String(cmd.getCommand()).include("+lively repl") ?
            cmd : null;
    },

    start: function(options, thenDo) {
        if (!thenDo) { thenDo = options; options = {}; }
        var port = options.port || "7888",
            self = this,
            cmdQueueName = "lively.clojure.replServer";

        Functions.composeAsync(
            function(next) { lively.require("lively.ide.CommandLineInterface").toRun(function() { next(); }); },
            this.stop.bind(this, port),
            this.ensureLivelyProfile.bind(this),
            function startServer(next) {
                var cmdString = Strings.format(
                    "lein with-profile +lively repl :headless :port %s", port);
                var cmd = lively.shell.run(cmdString, {group: cmdQueueName});
                next(null,cmd);
            },
            function waitForServerStart(cmd, next) {
                Functions.waitFor(5000, function() {
                    return cmd.getStdout().include("nREPL server started");
                }, function(err) { next(null, cmd); });
            }
        )(thenDo);
    },

    stop: function(port, thenDo) {
        port = port || "7888";
        var cmdQueueName = "lively.clojure.replServer";
        Functions.composeAsync(
            function clearLivelyClojureCommands(next) {
                var q = lively.shell.commandQueue[cmdQueueName];
                if (!q || !q[0]) return next();
                delete lively.shell.commandQueue[cmdQueueName];
                q[0].kill("SIGKILL", function(err, answer) { next(); });
            },
            function stopRunningServer(next) {
                var cmdString = Strings.format("lsof -i tcp:%s -t | xargs kill; ", port);
                lively.shell.run(cmdString, {group: cmdQueueName}, function(cmd) { next(); });
            }
        )(thenDo);
    },

    reset: function(thenDo) {
        Global.URL.nodejsBase.withFilename("ClojureServer/reset").asWebResource().beAsync()
            .post().whenDone(function(response, status) { thenDo(null,  show(status + '\n' + response)); });
    },

    ensureLivelyProfile: function(thenDo) {
        var profilesDir, livelyClojureProfileFile;
        var  livelyLeinProfile = this.livelyLeinProfile;
        Functions.composeAsync(
            function(next) {
                lively.shell.run("echo $HOME", {}, function(cmd) {
                    if (cmd.getCode()) next(cmd.resultString(true));
                    else {
                        var home = cmd.getStdout().trim()
                        profilesDir = home + "/.lein/profiles.d";
                        livelyClojureProfileFile = profilesDir + "/lively.clj";
                        next();
                    }
                });
            },
            function(next) {
                lively.shell.run("mkdir -p " + profilesDir, {}, function(cmd) { next(); });
            },
            function(next) {
                lively.ide.CommandLineInterface.writeFile(
                    livelyClojureProfileFile,
                    {content: livelyLeinProfile},
                    function() { next(); })
            }
        )(thenDo);
    }

});

Object.extend(lively.ide.codeeditor.modes.Clojure, {

    prettyPrint: function(code, thenDo) {
        // this is WORK IN PROGRESS!
        var prettify = Strings.format(
            "(require '(rewrite-clj parser printer))\n"
          + "(rewrite-clj.printer/print-edn (rewrite-clj.parser/parse-string-all \"%s\"))",
            code.replace(/"/g, '\\"'));

        // var prettify = Strings.format(
        //     "(clojure.pprint/write '%s :dispatch clojure.pprint/code-dispatch)",
        //     code);
        // var prettify = Strings.format(
        //     "(require '[fipp.edn :refer (pprint) :rename {pprint fipp}]) (fipp '%s)",
        //     code);

        lively.ide.codeeditor.modes.Clojure.doEval(
            prettify, {passError: true, resultIsJSON: false},
            function(err, prettified) {
                if (err) show(err);
                if (err) prettified = code;
                else {
                    // try { prettified = eval(prettified); } catch (e) { prettified = code; }
                    prettified = prettified.replace(/^(nil\s*)+/g, '');
                    // FIXME pretty printer seems to add additional newlines after comments
                    prettified = prettified.replace(/(;[^\n]*)[\n]+/gm, '$1\n');
                    if (!prettified.length) prettified = code;
                }
                thenDo && thenDo(err, prettified);
            });
    },

    fetchDoc: function(expr, thenDo) {
        this.doEval("(doc " + expr + ")", {prettyPrint: true}, thenDo);
    },

    doEval: function(expr, options, thenDo) {
        if (!thenDo) { thenDo = options; options = null; };
        options = options || {};
        var pp = options.prettyPrint;
        var isJSON = options.resultIsJSON;

        if (!module('lively.net.SessionTracker').isLoaded() || !lively.net.SessionTracker.isConnected()) {
            thenDo(new Error('Lively2Lively not running, cannot connect to Clojure nREPL server!'));
            return;
        }

        var sess = lively.net.SessionTracker.getSession();

        if (pp) expr = Strings.format("(with-out-str (>pprint (do %s)))", expr);

        sess.send('clojureEval', {code: expr}, function(answer) {
            if (answer.data.error) thenDo && thenDo(answer.data.error, null);
            else prepareRawResult(answer.data.result, thenDo); });

        // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
        function prepareRawResult(rawResult, thenDo) {
            if (!Object.isArray(rawResult) || !rawResult.length) return rawResult;
            var errors = rawResult.pluck("ex").compact(),
                isError = !!errors.length,
                result = rawResult.pluck('value').concat(rawResult.pluck('out')).compact().join('\n'),
                err = isError ? [errors, rawResult.pluck('root-ex'), rawResult.pluck('err')].flatten().compact().invoke('trim').uniq().join('\n') : null;

            if (!isError && pp) try { result = eval(result); } catch (e) {}
            if (!isError && isJSON) try { result = JSON.parse(eval(result)); } catch (e) {
                err = e;
                result = {error: e};
            }
            thenDo && thenDo(options.passError ? err : null, err || result);
        }
    }

});

var ClojureMode = lively.ide.ace.require('ace/mode/clojure').Mode;

ClojureMode.addMethods({

    commands: {
        prettyPrint: {
            exec: function(ed) {
                var string = ed.$morph.getSelectionOrLineString();
                lively.ide.codeeditor.modes.Clojure.prettyPrint(string, function(err, string) {
                    ed.insert(string);
                    // ed.$morph.printObject(ed, err ? err : string);
                });

            }
        },

        printDoc: {
            exec: function(ed) {
                var string = ed.$morph.getSelectionOrLineString();
                lively.ide.codeeditor.modes.Clojure.fetchDoc(string, function(err, docString) {
                    ed.$morph.printObject(ed, err ? err : docString);
                });
            }
        },
    },

    keybindings: {
        "Command-Shift-/": "printDoc",
        "Tab": "prettyPrint"
    },

    keyhandler: null,

    initKeyHandler: function() {
        Properties.forEachOwn(this.keybindings, function(key, commandName) {
            if (this.commands[commandName]) {
                if (this.commands[commandName].bindKey) {
                    var bound = this.commands[commandName].bindKey;
                    if (!Object.isArray(bound)) bound = [bound];
                    bound.push(key);
                    this.commands[commandName].bindKey = bound;
                } else this.commands[commandName].bindKey = key
            }
        }, this);
        return this.keyhandler = lively.ide.ace.createKeyHandler({
            keyBindings: this.keybindings,
            commands: this.commands
        });
    },

    attach: function(ed) {
        this.initKeyHandler();
        ed.keyBinding.addKeyboardHandler(this.keyhandler);
    },

    detach: function(ed) {
        ed.keyBinding.removeKeyboardHandler(this.keyhandler);
        this.keyhandler = null;
    },

    // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    doEval: function(codeEditor, insertResult) {
        var sourceString = codeEditor.getSelectionOrLineString();
        lively.ide.codeeditor.modes.Clojure.doEval(sourceString, {prettyPrint: true}, function(err, result) {
            printResult(err, result)
        });

        // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

        function printResult(err, result) {
            if (err && !Object.isString(err)) err = Objects.inspect(err, {maxDepth: 3});
            if (!insertResult && err) { codeEditor.world().alert(err); return;}
            if (result && !Object.isString(result)) result = Objects.inspect(result, {maxDepth: 3});
            if (insertResult) codeEditor.printObject(codeEditor.aceEditor, err ? err : result);
            else codeEditor.collapseSelection("end");
        }
    }
});

    }
});

}) // end of module
<commit_msg>clojure: starting to add clj AST support<commit_after>module('lively.ide.codeeditor.modes.Clojure').requires('lively.ide.codeeditor.ace').toRun(function() {

lively.ide.codeeditor.modes.Clojure.ReplServer = {};

Object.extend(lively.ide.codeeditor.modes.Clojure.ReplServer, {

    livelyLeinProfile: "{:plugins [[lein-pprint \"1.1.1\"]]\n"
                     + " :dependencies [[rksm/repl.utils \"0.1.1\"]\n"
                     + "                ;; for vinyasa lein\n"
                     + "                [leiningen #=(leiningen.core.main/leiningen-version)]\n"
                     + "                ;; trace execution\n"
                     + "                [org.clojure/tools.trace \"0.7.8\"]\n"
                     + "                ;; install dependencies / packages without restart\n"
                     + "                [com.cemerick/pomegranate \"0.3.0\"]\n"
                     + "                ;; cljs repl ++\n"
                     + "                [com.cemerick/piggieback \"0.1.4-SNAPSHOT\"]\n"
                     + "                ;; \"quick and dirty debugging\n"
                     + "                [spyscope \"0.1.4\"]\n"
                     + "                ;; reload namespaces, recursively tracking dependencies\n"
                     + "                [org.clojure/tools.namespace \"0.2.4\"]\n"
                     + "                ;; java reflection\n"
                     + "                [im.chit/iroh \"0.1.11\"]\n"
                     + "                ;; pretty stacktraces\n"
                     + "                [io.aviso/pretty \"0.1.8\"]\n"
                     + "                ;; inject stuff in namespace + other goodies\n"
                     + "                ;; see http://z.caudate.me/give-your-clojure-workflow-more-flow/\n"
                     + "                [im.chit/vinyasa \"0.2.2\"]]\n"
                     + " :injections [(require 'spyscope.core)\n"
                     + "              (require 'vinyasa.inject)\n"
                     + "              (require 'iroh.core)\n"
                     + "              (vinyasa.inject/in\n"
                     + "              clojure.core\n"
                     + "              [rksm.repl.utils lein search-for-symbol get-stack print-stack dumb-stack traced-fn]\n"
                     + "              [vinyasa.pull [pull pull]]\n"
                     + "              [clojure.java.shell sh]\n"
                     + "              [clojure.repl apropos dir doc find-doc source [root-cause cause]]\n"
                     + "              [clojure.tools.namespace.repl [refresh refresh]]\n"
                     + "              [clojure.pprint [pprint >pprint]]\n"
                     + "              [iroh.core .% .%> .*]\n"
                     + "              [clojure.tools.trace dotrace trace-ns untrace-ns])]}\n",

    ensure: function(options, thenDo) {
        if (!thenDo) { thenDo = options; options = {}; }
        var cmd = this.getCurrentServerCommand();
        if (cmd) {
            Functions.waitFor(5000, function() {
                return cmd.getStdout().include("nREPL server started");
            }, function(err) { thenDo(null, cmd); });
        } else this.start(options, thenDo);
    },

    getCurrentServerCommand: function() {
        var cmdQueueName = "lively.clojure.replServer";
        var q = lively.shell.commandQueue[cmdQueueName];
        var cmd = q && q[0];
        return cmd && String(cmd.getCommand()).include("+lively repl") ?
            cmd : null;
    },

    start: function(options, thenDo) {
        if (!thenDo) { thenDo = options; options = {}; }
        var port = options.port || "7888",
            self = this,
            cmdQueueName = "lively.clojure.replServer";

        Functions.composeAsync(
            function(next) { lively.require("lively.ide.CommandLineInterface").toRun(function() { next(); }); },
            this.stop.bind(this, port),
            this.ensureLivelyProfile.bind(this),
            function startServer(next) {
                var cmdString = Strings.format(
                    "lein with-profile +lively repl :headless :port %s", port);
                var cmd = lively.shell.run(cmdString, {group: cmdQueueName});
                next(null,cmd);
            },
            function waitForServerStart(cmd, next) {
                Functions.waitFor(5000, function() {
                    return cmd.getStdout().include("nREPL server started");
                }, function(err) { next(null, cmd); });
            }
        )(thenDo);
    },

    stop: function(port, thenDo) {
        port = port || "7888";
        var cmdQueueName = "lively.clojure.replServer";
        Functions.composeAsync(
            function clearLivelyClojureCommands(next) {
                var q = lively.shell.commandQueue[cmdQueueName];
                if (!q || !q[0]) return next();
                delete lively.shell.commandQueue[cmdQueueName];
                q[0].kill("SIGKILL", function(err, answer) { next(); });
            },
            function stopRunningServer(next) {
                var cmdString = Strings.format("lsof -i tcp:%s -t | xargs kill; ", port);
                lively.shell.run(cmdString, {group: cmdQueueName}, function(cmd) { next(); });
            }
        )(thenDo);
    },

    reset: function(thenDo) {
        Global.URL.nodejsBase.withFilename("ClojureServer/reset").asWebResource().beAsync()
            .post().whenDone(function(response, status) { thenDo(null,  show(status + '\n' + response)); });
    },

    ensureLivelyProfile: function(thenDo) {
        var profilesDir, livelyClojureProfileFile;
        var  livelyLeinProfile = this.livelyLeinProfile;
        Functions.composeAsync(
            function(next) {
                lively.shell.run("echo $HOME", {}, function(cmd) {
                    if (cmd.getCode()) next(cmd.resultString(true));
                    else {
                        var home = cmd.getStdout().trim()
                        profilesDir = home + "/.lein/profiles.d";
                        livelyClojureProfileFile = profilesDir + "/lively.clj";
                        next();
                    }
                });
            },
            function(next) {
                lively.shell.run("mkdir -p " + profilesDir, {}, function(cmd) { next(); });
            },
            function(next) {
                lively.ide.CommandLineInterface.writeFile(
                    livelyClojureProfileFile,
                    {content: livelyLeinProfile},
                    function() { next(); })
            }
        )(thenDo);
    }

});

Object.extend(lively.ide.codeeditor.modes.Clojure, {

    prettyPrint: function(code, thenDo) {
        // this is WORK IN PROGRESS!
        var prettify = Strings.format(
            "(require '(rewrite-clj parser printer))\n"
          + "(rewrite-clj.printer/print-edn (rewrite-clj.parser/parse-string-all \"%s\"))",
            code.replace(/"/g, '\\"'));

        // var prettify = Strings.format(
        //     "(clojure.pprint/write '%s :dispatch clojure.pprint/code-dispatch)",
        //     code);
        // var prettify = Strings.format(
        //     "(require '[fipp.edn :refer (pprint) :rename {pprint fipp}]) (fipp '%s)",
        //     code);

        lively.ide.codeeditor.modes.Clojure.doEval(
            prettify, {passError: true, resultIsJSON: false},
            function(err, prettified) {
                if (err) show(err);
                if (err) prettified = code;
                else {
                    // try { prettified = eval(prettified); } catch (e) { prettified = code; }
                    prettified = prettified.replace(/^(nil\s*)+/g, '');
                    // FIXME pretty printer seems to add additional newlines after comments
                    prettified = prettified.replace(/(;[^\n]*)[\n]+/gm, '$1\n');
                    if (!prettified.length) prettified = code;
                }
                thenDo && thenDo(err, prettified);
            });
    },

    fetchDoc: function(expr, thenDo) {
        this.doEval("(doc " + expr + ")", {prettyPrint: true}, thenDo);
    },

    doEval: function(expr, options, thenDo) {
        if (!thenDo) { thenDo = options; options = null; };
        options = options || {};
        var pp = options.prettyPrint;
        var isJSON = options.resultIsJSON;

        if (!module('lively.net.SessionTracker').isLoaded() || !lively.net.SessionTracker.isConnected()) {
            thenDo(new Error('Lively2Lively not running, cannot connect to Clojure nREPL server!'));
            return;
        }

        var sess = lively.net.SessionTracker.getSession();

        if (pp) expr = Strings.format("(with-out-str (>pprint (do %s)))", expr);

        sess.send('clojureEval', {code: expr}, function(answer) {
            if (answer.data.error) thenDo && thenDo(answer.data.error, null);
            else prepareRawResult(answer.data.result, thenDo); });

        // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
        function prepareRawResult(rawResult, thenDo) {
            if (!Object.isArray(rawResult) || !rawResult.length) return rawResult;
            var errors = rawResult.pluck("ex").compact(),
                isError = !!errors.length,
                result = rawResult.pluck('value').concat(rawResult.pluck('out')).compact().join('\n'),
                err = isError ? [errors, rawResult.pluck('root-ex'), rawResult.pluck('err')].flatten().compact().invoke('trim').uniq().join('\n') : null;

            if (!isError && pp) try { result = eval(result); } catch (e) {}
            if (!isError && isJSON) try { result = JSON.parse(eval(result)); } catch (e) {
                err = e;
                result = {error: e};
            }
            thenDo && thenDo(options.passError ? err : null, err || result);
        }
    }

});

var ClojureMode = lively.ide.ace.require('ace/mode/clojure').Mode;

ClojureMode.addMethods({

    commands: {
        prettyPrint: {
            exec: function(ed) {
                var string = ed.$morph.getSelectionOrLineString();
                lively.ide.codeeditor.modes.Clojure.prettyPrint(string, function(err, string) {
                    ed.insert(string);
                    // ed.$morph.printObject(ed, err ? err : string);
                });

            }
        },

        printDoc: {
            exec: function(ed) {
                var string = ed.$morph.getSelectionOrLineString();
                lively.ide.codeeditor.modes.Clojure.fetchDoc(string, function(err, docString) {
                    ed.$morph.printObject(ed, err ? err : docString);
                });
            }
        },
    },

    keybindings: {
        "Command-Shift-/": "printDoc",
        "Tab": "prettyPrint"
    },

    keyhandler: null,

    initKeyHandler: function() {
        Properties.forEachOwn(this.keybindings, function(key, commandName) {
            if (this.commands[commandName]) {
                if (this.commands[commandName].bindKey) {
                    var bound = this.commands[commandName].bindKey;
                    if (!Object.isArray(bound)) bound = [bound];
                    bound.push(key);
                    this.commands[commandName].bindKey = bound;
                } else this.commands[commandName].bindKey = key
            }
        }, this);
        return this.keyhandler = lively.ide.ace.createKeyHandler({
            keyBindings: this.keybindings,
            commands: this.commands
        });
    },

    attach: function(ed) {
        this.initKeyHandler();
        ed.keyBinding.addKeyboardHandler(this.keyhandler);
    },

    detach: function(ed) {
        ed.keyBinding.removeKeyboardHandler(this.keyhandler);
        this.keyhandler = null;
    },

    // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    doEval: function(codeEditor, insertResult) {
        var sourceString = codeEditor.getSelectionOrLineString();
        lively.ide.codeeditor.modes.Clojure.doEval(sourceString, {prettyPrint: true}, function(err, result) {
            printResult(err, result)
        });

        // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

        function printResult(err, result) {
            if (err && !Object.isString(err)) err = Objects.inspect(err, {maxDepth: 3});
            if (!insertResult && err) { codeEditor.world().alert(err); return;}
            if (result && !Object.isString(result)) result = Objects.inspect(result, {maxDepth: 3});
            if (insertResult) codeEditor.printObject(codeEditor.aceEditor, err ? err : result);
            else codeEditor.collapseSelection("end");
        }
    }
});

lively.ide.codeeditor.ModeChangeHandler.subclass('lively.ide.codeeditor.modes.Clojure.ChangeHandler',
"settings", {
    targetMode: "ace/mode/clojure"
},
"parsing", {
    parse: function(src, session) {
        var options = {};
        return null;
        // return closer.parse(src, options);
    }
},
'rendering', {

    onDocumentChange: function(evt) {
        this.updateAST(evt)
    },

    updateAST: function(evt) {
        var codeEditor = evt.codeEditor,
            session = evt.session,
            src = evt.codeEditor.textString,
            ast;

        // 1. parse
        try {
            ast = session.$ast = this.parse(src, session);
        } catch(e) { ast = session.$ast = e; }

        // 2. update lively codemarker
        var marker = this.ensureLivelyCodeMarker(session);
        marker.modeId = this.targetMode;
        marker.markerRanges.length = 0;

        // if (codeEditor.getShowWarnings()) {
        //     marker.markerRanges.pushAll(
        //         lively.ast.query.findGlobalVarRefs(ast, {jslintGlobalComment: true}).map(function(ea) {
        //             ea.cssClassName = "ace-global-var"; return ea; }));
        // }

        // if (ast.parseError && codeEditor.getShowErrors()) {
        //     ast.parseError.cssClassName = "ace-syntax-error";
        //     marker.markerRanges.push(ast.parseError);
        // }

        // marker.redraw(session);

        // 3. emit session astChange event
        var astChange = {ast: ast, docChange: evt.data, codeEditor: codeEditor};
        session._signal('astChange', astChange);
    }

});

(function registerModeHandler() {
    lively.module('lively.ide.codeeditor.DocumentChange').runWhenLoaded(function() {
        lively.ide.CodeEditor.DocumentChangeHandler.registerModeHandler(lively.ide.codeeditor.modes.Clojure.ChangeHandler);
    });
})();

}) // end of module
<|endoftext|>


<commit_before>var hqLayout = {};

hqLayout.selector = {
    navigation: '#hq-navigation',
    content: '#hq-content',
    appmanager: '#js-appmanager-body.appmanager-content-not-formdesigner',
    footer: '#hq-footer',
    sidebar: '#hq-sidebar',
    breadcrumbs: '#hq-breadcrumbs',
    messages: '#hq-messages-container',
};

hqLayout.values = {
    footerHeight: 0,
    isFooterVisible: true,
    isAppbuilderResizing: false,
};

hqLayout.utils = {
    getCurrentScrollPosition: function () {
        return $(window).scrollTop() + $(window).height();
    },
    getFooterShowPosition: function () {
        return $(document).height() - (hqLayout.values.footerHeight / 3);
    },
    getAvailableContentWidth: function () {
        var $sidebar = $(hqLayout.selector.sidebar);
        // todo fix extra 10 px padding needed when sidebar suddenly disappears
        // on modal.
        var absorbedWidth = $sidebar.outerWidth();
        return $(window).outerWidth() - absorbedWidth;
    },
    getAvailableContentHeight: function () {
        var $navigation = $(hqLayout.selector.navigation),
            $footer = $(hqLayout.selector.footer),
            $breadcrumbs = $(hqLayout.selector.breadcrumbs),
            $messages = $(hqLayout.selector.messages);

        var absorbedHeight = $navigation.outerHeight() + $footer.outerHeight();
        if ($breadcrumbs.length) {
            absorbedHeight += $breadcrumbs.outerHeight();
        }
        if ($messages.length) {
            absorbedHeight += $messages.outerHeight();
        }
        return $(window).height() - absorbedHeight;
    },
    isScrolledToFooter: function () {
        return hqLayout.utils.getCurrentScrollPosition() >= hqLayout.utils.getFooterShowPosition();
    },
    isScrollable: function () {
        return $(document).height() > $(window).height();
    },
    setIsAppbuilderResizing: function (isOn) {
        hqLayout.values.isAppbuilderResizing = isOn;
    },
    setBalancePreviewFn: function (fn) {
        hqLayout.actions.balancePreview = fn;
    }
};

hqLayout.actions = {
    initialize: function () {
        hqLayout.values.footerHeight = $(hqLayout.selector.footer).innerHeight();
    },
    balanceSidebar: function () {
        var $sidebar = $(hqLayout.selector.sidebar),
            $content = $(hqLayout.selector.content),
            $appmanager = $(hqLayout.selector.appmanager);

        if ($appmanager.length) {
            var availableHeight = hqLayout.utils.getAvailableContentHeight(),
                contentHeight = $appmanager.outerHeight();

            if ($sidebar.length) {
                var newSidebarHeight = Math.max(availableHeight, contentHeight);
                $sidebar.css('min-height', newSidebarHeight + 'px');

                if ($sidebar.outerHeight() >  $appmanager.outerHeight()) {
                    $content.css('min-height', $sidebar.outerHeight() + 'px');
                    $appmanager.css('min-height', $sidebar.outerHeight() + 'px');
                }
            }

        } else if ($content.length) {
            var availableHeight = hqLayout.utils.getAvailableContentHeight(),
                contentHeight = $content.innerHeight();

            if (contentHeight > availableHeight) {
                $content.css('padding-bottom', 15 + 'px');
                contentHeight = $content.outerHeight();
            }

            if ($sidebar.length && !hqLayout.values.isAppbuilderResizing) {
                var newSidebarHeight = Math.max(availableHeight, contentHeight);
                $sidebar.css('min-height', newSidebarHeight + 'px');
            } else {
                if ($sidebar.outerHeight() >  $content.outerHeight()) {
                    $content.css('min-height', $sidebar.outerHeight() + 'px');
                }
            }
        }
    },
    balanceWidths: function () {
        var $content = $(hqLayout.selector.content),
            $sidebar = $(hqLayout.selector.sidebar),
            $appmanager = $(hqLayout.selector.appmanager);

        if ($content.length && $sidebar.length && $appmanager.length === 0) {
            $content.css('width', hqLayout.utils.getAvailableContentWidth() + 'px');
        }

    },
    balancePreview: function () {
        // set with setBalancePreviewFn in utils.
    }
};

$(window).on('load', function () {
    hqLayout.actions.initialize();
    if (hqLayout.values.isAppbuilderResizing) {
        hqLayout.actions.balanceWidths();
    }
    hqLayout.actions.balanceSidebar();
    hqLayout.actions.balancePreview();
});

$(window).resize(function () {
    if (hqLayout.values.isAppbuilderResizing) {
        hqLayout.actions.balanceWidths();
    }
    hqLayout.actions.balanceSidebar();
    hqLayout.actions.balancePreview();
});

$(window).scroll(function () {
    hqLayout.actions.balanceSidebar();
});
<commit_msg>Fix gaps in v1 form builder<commit_after>var hqLayout = {};

hqLayout.selector = {
    navigation: '#hq-navigation',
    content: '#hq-content',
    appmanager: '#js-appmanager-body.appmanager-content-not-formdesigner',
    footer: '#hq-footer',
    sidebar: '#hq-sidebar',
    breadcrumbs: '#hq-breadcrumbs',
    messages: '#hq-messages-container',
};

hqLayout.values = {
    footerHeight: 0,
    isFooterVisible: true,
    isAppbuilderResizing: false,
};

hqLayout.utils = {
    getCurrentScrollPosition: function () {
        return $(window).scrollTop() + $(window).height();
    },
    getFooterShowPosition: function () {
        return $(document).height() - (hqLayout.values.footerHeight / 3);
    },
    getAvailableContentWidth: function () {
        var $sidebar = $(hqLayout.selector.sidebar);
        // todo fix extra 10 px padding needed when sidebar suddenly disappears
        // on modal.
        var absorbedWidth = $sidebar.outerWidth();
        return $(window).outerWidth() - absorbedWidth;
    },
    getAvailableContentHeight: function () {
        var $navigation = $(hqLayout.selector.navigation),
            $footer = $(hqLayout.selector.footer),
            $breadcrumbs = $(hqLayout.selector.breadcrumbs),
            $messages = $(hqLayout.selector.messages);

        var absorbedHeight = $navigation.outerHeight() + $footer.outerHeight();
        if ($breadcrumbs.length) {
            absorbedHeight += $breadcrumbs.outerHeight();
        }
        if ($messages.length) {
            absorbedHeight += $messages.outerHeight();
        }
        return $(window).height() - absorbedHeight;
    },
    isScrolledToFooter: function () {
        return hqLayout.utils.getCurrentScrollPosition() >= hqLayout.utils.getFooterShowPosition();
    },
    isScrollable: function () {
        return $(document).height() > $(window).height();
    },
    setIsAppbuilderResizing: function (isOn) {
        hqLayout.values.isAppbuilderResizing = isOn;
    },
    setBalancePreviewFn: function (fn) {
        hqLayout.actions.balancePreview = fn;
    }
};

hqLayout.actions = {
    initialize: function () {
        hqLayout.values.footerHeight = $(hqLayout.selector.footer).innerHeight();
    },
    balanceSidebar: function () {
        var $sidebar = $(hqLayout.selector.sidebar),
            $content = $(hqLayout.selector.content),
            $appmanager = $(hqLayout.selector.appmanager);

        if ($appmanager.length) {
            var availableHeight = hqLayout.utils.getAvailableContentHeight(),
                contentHeight = $appmanager.outerHeight();

            if ($sidebar.length) {
                var newSidebarHeight = Math.max(availableHeight, contentHeight);
                $sidebar.css('min-height', newSidebarHeight + 'px');

                if ($sidebar.outerHeight() >  $appmanager.outerHeight()) {
                    $content.css('min-height', $sidebar.outerHeight() + 'px');
                    $appmanager.css('min-height', $sidebar.outerHeight() + 'px');
                }
            }

        } else if ($content.length) {
            var availableHeight = hqLayout.utils.getAvailableContentHeight(),
                contentHeight = $content.innerHeight();

            if (contentHeight > availableHeight) {
                $content.css('padding-bottom', 15 + 'px');
                contentHeight = $content.outerHeight();
            }

            if ($sidebar.length && !hqLayout.values.isAppbuilderResizing) {
                var newSidebarHeight = Math.max(availableHeight, contentHeight);
                $sidebar.css('min-height', newSidebarHeight + 'px');
            } else {
                if ($sidebar.outerHeight() >  $content.outerHeight()) {
                    $content.css('min-height', $sidebar.outerHeight() + 'px');
                }
            }

            if ($content.find("#formdesigner").length && !COMMCAREHQ.toggleEnabled('APP_MANAGER_V2')) {
                $content.css("padding-left", 0);
                $content.css("padding-right", 0);
            }
        }
    },
    balanceWidths: function () {
        var $content = $(hqLayout.selector.content),
            $sidebar = $(hqLayout.selector.sidebar),
            $appmanager = $(hqLayout.selector.appmanager);

        if ($content.length && $sidebar.length && $appmanager.length === 0) {
            $content.css('width', hqLayout.utils.getAvailableContentWidth() + 'px');
        }

    },
    balancePreview: function () {
        // set with setBalancePreviewFn in utils.
    }
};

$(window).on('load', function () {
    hqLayout.actions.initialize();
    if (hqLayout.values.isAppbuilderResizing) {
        hqLayout.actions.balanceWidths();
    }
    hqLayout.actions.balanceSidebar();
    hqLayout.actions.balancePreview();
});

$(window).resize(function () {
    if (hqLayout.values.isAppbuilderResizing) {
        hqLayout.actions.balanceWidths();
    }
    hqLayout.actions.balanceSidebar();
    hqLayout.actions.balancePreview();
});

$(window).scroll(function () {
    hqLayout.actions.balanceSidebar();
});
<|endoftext|>


<commit_before>
/**
 * This file of tests only gets executed by Travis CI
 */

describe('Impersonate user JWT, navigate to profile, edit last_name to & back.', function () {

    context('Wrangler User Profile', function () {

        before(function(){
            cy.visit('/');
        });

        /** Cypress clears browser state between tests so need to use beforeEach rather than before. This may change according to Cypress - https://github.com/cypress-io/cypress/issues/747 */
        /*
        beforeEach(function(){
            cy.login4DN({ 'email' : 'wrangler@wrangler.com' });
        });
        */

        it('Ensure logged in, visit profile page, edit last name 2x.', function(){

            cy.login4DN({ 'email' : 'wrangler@wrangler.com', 'useEnvToken' : false }).end().get('ul.navbar-acct li.user-account-item').should('have.class', 'is-logged-in').then((accountListItem)=>{
                expect(accountListItem.children('#user_actions_dropdown').text()).to.contain('Wrangler');
            }).end()
            .get("#user_actions_dropdown").click().wait(100).end()
            .get('ul.dropdown-menu[aria-labelledby="user_actions_dropdown"] a#profile').click().end()
            .get('.page-container .user-title-row-container h1.user-title').invoke('text').should('include', "Wrangler").end() // Test only for first name as we're editing last name & it may change re: delayed indexing, etc.
            // Edit wrangler last name
            .get('.page-container .user-title-row-container h1.user-title .last_name .value.saved a.edit-button').click().end()
            .get('.page-container .user-title-row-container h1.user-title .last_name .value.editing input').clear().type('SuperWrangler').then((inputfield)=>{
                //inputfield.type('SuperWrangler');
                return cy.wait(100).get('.page-container .user-title-row-container h1.user-title .last_name .value.editing .save-button').click().end()
                .get('.page-container .user-title-row-container h1.user-title').should('have.text', "Wrangler SuperWrangler").end()
                .url().then((currUrl)=>{ // After reloading on datastore=database, last name stays edited. Then change back.
                    return cy.visit(currUrl + '?datastore=database').end()
                    .get('.page-container .user-title-row-container h1.user-title').should('have.text', "Wrangler SuperWrangler").end()
                    // Cleanup & test again
                    .get('.page-container .user-title-row-container h1.user-title .last_name .value.saved a.edit-button').click().end()
                    .get('.page-container .user-title-row-container h1.user-title .last_name .value.editing input').should('have.value', 'SuperWrangler').clear().type('Wrangler').then((inputfield)=>{
                        return cy.wait(100)
                        .get('.page-container .user-title-row-container h1.user-title .last_name .value.editing .save-button').click().end()
                        .get('.page-container .user-title-row-container h1.user-title').should('have.text', "Wrangler Wrangler").end()
                        //.reload()
                        //.get('.page-container .user-title-row-container h1.user-title').should('have.text', "Wrangler Wrangler").end();
                    });

                });

            });

        });

    });

});
<commit_msg>Add wait time for JS to exec.<commit_after>
/**
 * This file of tests only gets executed by Travis CI
 */

describe('Impersonate user JWT, navigate to profile, edit last_name to & back.', function () {

    context('Wrangler User Profile', function () {

        before(function(){
            cy.visit('/');
        });

        /** Cypress clears browser state between tests so need to use beforeEach rather than before. This may change according to Cypress - https://github.com/cypress-io/cypress/issues/747 */
        /*
        beforeEach(function(){
            cy.login4DN({ 'email' : 'wrangler@wrangler.com' });
        });
        */

        it('Ensure logged in, visit profile page, edit last name 2x.', function(){

            cy.login4DN({ 'email' : 'wrangler@wrangler.com', 'useEnvToken' : false }).end().get('ul.navbar-acct li.user-account-item').should('have.class', 'is-logged-in').then((accountListItem)=>{
                expect(accountListItem.children('#user_actions_dropdown').text()).to.contain('Wrangler');
            }).end()
            .get("#user_actions_dropdown").click().wait(100).end()
            .get('ul.dropdown-menu[aria-labelledby="user_actions_dropdown"] a#profile').click().end()
            .get('.page-container .user-title-row-container h1.user-title').invoke('text').should('include', "Wrangler").end() // Test only for first name as we're editing last name & it may change re: delayed indexing, etc.
            // Edit wrangler last name
            .get('.page-container .user-title-row-container h1.user-title .last_name .value.saved a.edit-button').click().end()
            .get('.page-container .user-title-row-container h1.user-title .last_name .value.editing input').clear().type('SuperWrangler').then((inputfield)=>{
                //inputfield.type('SuperWrangler');
                return cy.wait(100).get('.page-container .user-title-row-container h1.user-title .last_name .value.editing .save-button').click()
                .should('have.length', 0).wait(100).end()
                .get('.page-container .user-title-row-container h1.user-title').should('have.text', "Wrangler SuperWrangler").end()
                .url().then((currUrl)=>{ // After reloading on datastore=database, last name stays edited. Then change back.
                    return cy.visit(currUrl + '?datastore=database').end()
                    .get('.page-container .user-title-row-container h1.user-title').should('have.text', "Wrangler SuperWrangler").end()
                    // Cleanup & test again
                    .get('.page-container .user-title-row-container h1.user-title .last_name .value.saved a.edit-button').click().end()
                    .get('.page-container .user-title-row-container h1.user-title .last_name .value.editing input').should('have.value', 'SuperWrangler').clear().type('Wrangler').then((inputfield)=>{
                        return cy.wait(100)
                        .get('.page-container .user-title-row-container h1.user-title .last_name .value.editing .save-button').click()
                        .should('have.length', 0).wait(100).end()
                        .get('.page-container .user-title-row-container h1.user-title').should('have.text', "Wrangler Wrangler").end();
                        //.reload()
                        //.get('.page-container .user-title-row-container h1.user-title').should('have.text', "Wrangler Wrangler").end();
                    });

                });

            });

        });

    });

});
<|endoftext|>