<commit_before>(function() {

    CodeMirror.xmlHints = [];

    CodeMirror.xmlHint = function(cm) {

        var cursor = cm.getCursor();

        if (cursor.ch > 0) {

            var text = cm.getRange(CodeMirror.Pos(0, 0), cursor);
            var typed = '';
            var simbol = '';
            for(var i = text.length - 1; i >= 0; i--) {
                if(text[i] == ' ' || text[i] == '<') {
                    simbol = text[i];
                    break;
                }
                else {
                    typed = text[i] + typed;
                }
            }

            text = text.slice(0, text.length - typed.length);

            var path = getActiveElement(text) + simbol;
            var hints = CodeMirror.xmlHints[path];

            if(typeof hints === 'undefined')
                hints = [''];
            else {
                hints = hints.slice(0);
                for (var i = hints.length - 1; i >= 0; i--) {
                    if(hints[i].indexOf(typed) != 0)
                        hints.splice(i, 1);
                }
            }

            return {
                list: hints,
                from: CodeMirror.Pos(cursor.line, cursor.ch - typed.length),
                to: cursor
            };
        }
    };

    var getActiveElement = function(text) {

        var element = '';

        if(text.length >= 0) {

            var regex = new RegExp('<([^!?][^\\s/>]*).*?>', 'g');

            var matches = [];
            var match;
            while ((match = regex.exec(text)) != null) {
                matches.push({
                    tag: match[1],
                    selfclose: (match[0].slice(match[0].length - 2) === '/>')
                });
            }

            for (var i = matches.length - 1, skip = 0; i >= 0; i--) {

                var item = matches[i];

                if (item.tag[0] == '/')
                {
                    skip++;
                }
                else if (item.selfclose == false)
                {
                    if (skip > 0)
                    {
                        skip--;
                    }
                    else
                    {
                        element = '<' + item.tag + '>' + element;
                    }
                }
            }

            element += getOpenTag(text);
        }

        return element;
    };

    var getOpenTag = function(text) {

        var open = text.lastIndexOf('<');
        var close = text.lastIndexOf('>');

        if (close < open)
        {
            text = text.slice(open);

            if(text != '<') {

                var space = text.indexOf(' ');
                if(space < 0)
                    space = text.indexOf('\t');
                if(space < 0)
                    space = text.indexOf('\n');

                if (space < 0)
                    space = text.length;

                return text.slice(0, space);
            }
        }

        return '';
    };

})();
<commit_msg>[xml-hint addon] Recognize multi-line tags<commit_after>(function() {

    CodeMirror.xmlHints = [];

    CodeMirror.xmlHint = function(cm) {

        var cursor = cm.getCursor();

        if (cursor.ch > 0) {

            var text = cm.getRange(CodeMirror.Pos(0, 0), cursor);
            var typed = '';
            var simbol = '';
            for(var i = text.length - 1; i >= 0; i--) {
                if(text[i] == ' ' || text[i] == '<') {
                    simbol = text[i];
                    break;
                }
                else {
                    typed = text[i] + typed;
                }
            }

            text = text.slice(0, text.length - typed.length);

            var path = getActiveElement(text) + simbol;
            var hints = CodeMirror.xmlHints[path];

            if(typeof hints === 'undefined')
                hints = [''];
            else {
                hints = hints.slice(0);
                for (var i = hints.length - 1; i >= 0; i--) {
                    if(hints[i].indexOf(typed) != 0)
                        hints.splice(i, 1);
                }
            }

            return {
                list: hints,
                from: CodeMirror.Pos(cursor.line, cursor.ch - typed.length),
                to: cursor
            };
        }
    };

    var getActiveElement = function(text) {

        var element = '';

        if(text.length >= 0) {

            var regex = new RegExp('<([^!?][^\\s/>]*)[\\s\\S]*?>', 'g');

            var matches = [];
            var match;
            while ((match = regex.exec(text)) != null) {
                matches.push({
                    tag: match[1],
                    selfclose: (match[0].slice(match[0].length - 2) === '/>')
                });
            }

            for (var i = matches.length - 1, skip = 0; i >= 0; i--) {

                var item = matches[i];

                if (item.tag[0] == '/')
                {
                    skip++;
                }
                else if (item.selfclose == false)
                {
                    if (skip > 0)
                    {
                        skip--;
                    }
                    else
                    {
                        element = '<' + item.tag + '>' + element;
                    }
                }
            }

            element += getOpenTag(text);
        }

        return element;
    };

    var getOpenTag = function(text) {

        var open = text.lastIndexOf('<');
        var close = text.lastIndexOf('>');

        if (close < open)
        {
            text = text.slice(open);

            if(text != '<') {

                var space = text.indexOf(' ');
                if(space < 0)
                    space = text.indexOf('\t');
                if(space < 0)
                    space = text.indexOf('\n');

                if (space < 0)
                    space = text.length;

                return text.slice(0, space);
            }
        }

        return '';
    };

})();
<|endoftext|>


<commit_before>import Ember from 'ember';
import baseMixin from 'ember-data-offline/mixins/base';
import debug from 'ember-data-offline/utils/debug';

export default Ember.Mixin.create(baseMixin, {
  shouldReloadAll() {
    return false;
  },
  shouldBackgroundReloadAll: function() {
    return false;
  },

  findAll: function(store, typeClass, sinceToken, fromJob) {
    debug('findAll online', typeClass.modelName);
    let adapterResp = this._super.apply(this, arguments);
    return adapterResp.then(resp => {
      //TODO Think about persistance this registry hash
      this.set(`lastTimeFetched.all$${typeClass.modelName}`, new Date());
      if (!fromJob) {
        this.createOfflineJob('findAll', [store, typeClass, sinceToken, adapterResp, true], store);
      }
      return resp;
    });
  },

  find: function(store, typeClass, id, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    return onlineResp.then(resp => {
      this.set(`lastTimeFetched.one$${typeClass.modelName}$${id}`, new Date());
      if (!fromJob) {
        this.createOfflineJob('find', [store, typeClass, id], store);
      }
      return resp;
    }).catch(console.log.bind(console));
  },

  findQuery: function(store, type, query, recordArray, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    return onlineResp.then(resp => {
      if (!fromJob) {
        this.createOfflineJob('findQuery', [store, type, query, resp, true], store);
      }
      return resp;
    });
  },

  findMany: function(store, typeClass, ids, snapshots, fromJob) {
    //TODO add some config param for such behavior
    let onlineResp = this.findAll(store, typeClass, null, true);

    return onlineResp.then(resp => {
      if (!fromJob) {
        this.createOfflineJob('findMany', [store, typeClass, ids], store);
      }
      return resp;
    });
  },

  createRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      //this.createOfflineJob('createRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  },

  updateRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      //this.createOfflineJob('updateRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  },

  deleteRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      //this.createOfflineJob('deleteRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  }
});
<commit_msg>Update online.js<commit_after>import Ember from 'ember';
import baseMixin from 'ember-data-offline/mixins/base';
import debug from 'ember-data-offline/utils/debug';

export default Ember.Mixin.create(baseMixin, {
  shouldReloadAll() {
    return false;
  },
  shouldBackgroundReloadAll: function() {
    return false;
  },

  findAll: function(store, typeClass, sinceToken, fromJob) {
    debug('findAll online', typeClass.modelName);
    let adapterResp = this._super.apply(this, arguments);
    return adapterResp.then(resp => {
      //TODO Think about persistance this registry hash
      this.set(`lastTimeFetched.all$${typeClass.modelName}`, new Date());
      if (!fromJob) {
        this.createOfflineJob('findAll', [store, typeClass, sinceToken, adapterResp, true], store);
      }
      return resp;
    });
  },

  find: function(store, typeClass, id, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    return onlineResp.then(resp => {
      this.set(`lastTimeFetched.one$${typeClass.modelName}$${id}`, new Date());
      if (!fromJob) {
        this.createOfflineJob('find', [store, typeClass, id], store);
      }
      return resp;
    }).catch(console.log.bind(console));
  },

  findQuery: function(store, type, query, recordArray, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    return onlineResp.then(resp => {
      if (!fromJob) {
        this.createOfflineJob('findQuery', [store, type, query, resp, true], store);
      }
      return resp;
    });
  },

  findMany: function(store, typeClass, ids, snapshots, fromJob) {
    //TODO add some config param for such behavior
    let onlineResp = this.findAll(store, typeClass, null, true);

    return onlineResp.then(resp => {
      if (!fromJob) {
        this.createOfflineJob('findMany', [store, typeClass, ids], store);
      }
      return resp;
    });
  },

  createRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('createRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  },

  updateRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('updateRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  },

  deleteRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('deleteRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  }
});
<|endoftext|>


<commit_before>/* global require, requirejs */
import Em from 'ember';
import DS from 'ember-data';
import { getContext } from 'ember-test-helpers';

var modelFactory;

var ModelFactory = Em.Object.extend({
    numCreated: 0,
    ctx: null,
    store: null,
    resolver: null,
    modulePrefix: '',
    init: function(){
        this.setup();
    },
    setup: function(){
        this._initCtx();
        this._initStore();
        if(this.get('_isSetup')){
            this._registerModelsAndTransforms();
        }
    },
    teardown: function(){
        var factory = this;
        Em.run(function(){
            factory.clearStore();
            factory.set('store', null);
            factory.set('ctx', null);
            factory.set('_modules', {});
        });
    },
    defineTemplateMap: function(factoryName, templates){
        this.set('_templates.' + factoryName, templates);
    },
    createRecord: function(modelName, typeParam, customRecordId){
        typeParam = typeParam || 'index';
        var store = this.get('store'),
            record = null,
            modelTemplate, recordTemplate;
        if(typeof typeParam === 'string'){
            // If typeParam is a string, try to look up the template.
            modelTemplate = this._lookupTemplate(modelName, typeParam);
        }else{
            // if typeParam is not a string, assume it is a custom object and create model.
            modelTemplate = typeParam;
        }

        // copy the template so we do not modify the original...
        recordTemplate = Em.$.extend({}, modelTemplate);
        if(customRecordId !== undefined){
            recordTemplate.id = customRecordId;
        }else{
            if(recordTemplate.id === undefined){
                recordTemplate.id = this._makeRecordId(modelName);
            }
        }
        Em.run(function(){
            record = store.push(modelName, recordTemplate);
        });
        return record;
    },
    createRecordList: function(modelName, count, typeParams, customIds){
        typeParams = typeParams || 'index';
        customIds = customIds || [];
        var i = 0, records = Em.A();
        if(typeof typeParams === 'string'){
            // If typeParams is a string, just create a list of records with same template...
            for(i = 0; i < count; i++){
                records.addObject(this.createRecord(modelName, typeParams));
            }
        }else{
            // If typeParams is NOT a string, assume it is an array and create each record with specified type...
            for(i = 0; i < count; i++){
                records.addObject(this.createRecord(modelName, typeParams[i], customIds[i]));
            }
        }
        return records;
    },
    clearStore: function(){
        var store = this.get('store'),
            typeKey;
        if(store){
            // Loop through model types in store, and unload records for each type.
            for(typeKey in store.typeMaps){
                if(store.typeMaps.hasOwnProperty(typeKey)){
                    store.unloadAll(store.typeMaps[typeKey].type.modelName);
                }
            }
        }
    },
    _lookupTemplate: function(modelName, templateKey){
        templateKey = templateKey || 'index';
        return this.get('_templates.' + modelName + '.' + templateKey) || {};
    },
    _templates: {},
    _modules: {},
    _initCtx: function(){
        // Set 'ctx' to context of current test...
        this.set('ctx', getContext());
    },
    _initStore: function(){
        // Set 'store' to the DS.Store from the application container for the test.
        var ctx = this.get('ctx') || {},
            container = ctx.container,
            store = null;
        if(container){
            store = container.lookup('service:store');
            Em.assert('Model Factory requires an actual DS.Store to initialize.  ' +
                'Is the store injected into the unit that you are testing?', store instanceof DS.Store);
            this.set('store', store);
        }
    },
    _registerFactory: function(factoryName){
        // Requires the factory if it does not already exist so it calls define(factoryName)...
        if(!this.get('_templates.' + factoryName)){
            try{
                require(this.get('modulePrefix') + '/tests/factories/' + factoryName);
            }catch(e){
                console.warn('Could not find factory for ' + factoryName);
            }
        }
    },
    _registerDependency: function(type, name){
        if(type === 'model'){
            this._registerFactory(name);
        }
        // Registers a dependency for the test (DS.Transform or DS.Model)...
        var moduleName = type + ':' + name,
            resolver = this.get('resolver'),
            normalizedModuleName = resolver.normalize(moduleName),
            ctx = this.get('ctx'),
            module = resolver.resolve(normalizedModuleName),
            registry = ctx.registry || ctx.container;
        if(!registry.registrations[normalizedModuleName]){
            registry.register(moduleName, module);
        }
        return module;
    },
    _registerModelsAndTransforms: function(){
        var entries = requirejs.entries,
            modelPrefix = this.get('modulePrefix') + '/models/',
            transformPrefix = this.get('modulePrefix') + '/transforms/',
            entry;
        for(entry in entries){
            if(entries.hasOwnProperty(entry)){
                if(entry.indexOf(modelPrefix) > -1){
                    this._registerDependency('model', entry.replace(modelPrefix, ''));
                }else if(entry.indexOf(transformPrefix) > -1){
                    this._registerDependency('transform', entry.replace(transformPrefix, ''));
                }
            }
        }
    },
    _makeRecordId: function(modelName){
        this.incrementProperty('numCreated');
        return modelName + this.get('numCreated') + '-' + Date.now();
    },
    _isSetup: Em.computed('ctx', 'store', function(){
        return this.get('ctx') && this.get('store');
    })
});

modelFactory = ModelFactory.create();

export default {
    setResolver: function(resolver){
        modelFactory.set('resolver', resolver);
    },
    setModulePrefix: function(prefix){
        modelFactory.set('modulePrefix', prefix);
    },
    setup: function(){
        if(!modelFactory.get('_isSetup')){
            modelFactory.setup();
        }
    },
    teardown: function(){
        modelFactory.teardown();
    },
    define: function(modelName, templateMap){
        templateMap = templateMap || {};
        modelFactory.defineTemplateMap(modelName, templateMap);
    },

    // context & store are unavailable during very first test, due to the the global 'beforeEach' loop is run prior to
    // the app being setup.  To get around this, calling setup once more when createRecord is called to make sure
    // that the model factory is completely setup.
    createRecord: function(modelName, typeParam, customId){
        this.setup();
        return modelFactory.createRecord(modelName, typeParam, customId);
    },
    createRecordList: function(modelName, count, typeParams, customIds){
        this.setup();
        return modelFactory.createRecordList(modelName, count, typeParams, customIds);
    }
};
<commit_msg>overriding save method of models<commit_after>/* global require, requirejs */
import Em from 'ember';
import DS from 'ember-data';
import { getContext } from 'ember-test-helpers';

var modelFactory;

var ModelFactory = Em.Object.extend({
    numCreated: 0,
    ctx: null,
    store: null,
    resolver: null,
    modulePrefix: '',
    init: function(){
        this.setup();
    },
    setup: function(){
        this._initCtx();
        this._initStore();
        if(this.get('_isSetup')){
            this._registerModelsAndTransforms();
        }
    },
    teardown: function(){
        var factory = this;
        Em.run(function(){
            factory.clearStore();
            factory.set('store', null);
            factory.set('ctx', null);
            factory.set('_modules', {});
        });
    },
    defineTemplateMap: function(factoryName, templates){
        this.set('_templates.' + factoryName, templates);
    },
    createRecord: function(modelName, typeParam, customRecordId){
        typeParam = typeParam || 'index';
        var factory = this,
            store = this.get('store'),
            record = null,
            modelTemplate, recordTemplate;
        if(typeof typeParam === 'string'){
            // If typeParam is a string, try to look up the template.
            modelTemplate = this._lookupTemplate(modelName, typeParam);
        }else{
            // if typeParam is not a string, assume it is a custom object and create model.
            modelTemplate = typeParam;
        }

        // copy the template so we do not modify the original...
        recordTemplate = Em.$.extend({}, modelTemplate);
        if(customRecordId !== undefined){
            recordTemplate.id = customRecordId;
        }else{
            if(recordTemplate.id === undefined){
                recordTemplate.id = this._makeRecordId(modelName);
            }
        }
        Em.run(function(){
            record = store.push(modelName, recordTemplate);
            factory._overrideModelMethods(record);
        });
        return record;
    },
    _overrideModelMethods: function(record){
        // This method overrides Ember Data methods that will cause errors with mocked records...
        record.save = function(){ return record; };
    },
    createRecordList: function(modelName, count, typeParams, customIds){
        typeParams = typeParams || 'index';
        customIds = customIds || [];
        var i = 0, records = Em.A();
        if(typeof typeParams === 'string'){
            // If typeParams is a string, just create a list of records with same template...
            for(i = 0; i < count; i++){
                records.addObject(this.createRecord(modelName, typeParams));
            }
        }else{
            // If typeParams is NOT a string, assume it is an array and create each record with specified type...
            for(i = 0; i < count; i++){
                records.addObject(this.createRecord(modelName, typeParams[i], customIds[i]));
            }
        }
        return records;
    },
    clearStore: function(){
        var store = this.get('store'),
            typeKey;
        if(store){
            // Loop through model types in store, reset dirty states, and unload records for each type.
            for(typeKey in store.typeMaps){
                if(store.typeMaps.hasOwnProperty(typeKey)){
                    // unload records by type...
                    store.unloadAll(store.typeMaps[typeKey].type.modelName);
                }
            }
        }
    },
    _lookupTemplate: function(modelName, templateKey){
        templateKey = templateKey || 'index';
        return this.get('_templates.' + modelName + '.' + templateKey) || {};
    },
    _templates: {},
    _modules: {},
    _initCtx: function(){
        // Set 'ctx' to context of current test...
        this.set('ctx', getContext());
    },
    _initStore: function(){
        // Set 'store' to the DS.Store from the application container for the test.
        var ctx = this.get('ctx') || {},
            container = ctx.container,
            store = null;
        if(container){
            store = container.lookup('service:store');
            Em.assert('Model Factory requires an actual DS.Store to initialize.  ' +
                'Is the store injected into the unit that you are testing?', store instanceof DS.Store);
            this.set('store', store);
        }
    },
    _registerFactory: function(factoryName){
        // Requires the factory if it does not already exist so it calls define(factoryName)...
        if(!this.get('_templates.' + factoryName)){
            try{
                require(this.get('modulePrefix') + '/tests/factories/' + factoryName);
            }catch(e){
                console.warn('Could not find factory for ' + factoryName);
            }
        }
    },
    _registerDependency: function(type, name){
        if(type === 'model'){
            this._registerFactory(name);
        }
        // Registers a dependency for the test (DS.Transform or DS.Model)...
        var moduleName = type + ':' + name,
            resolver = this.get('resolver'),
            normalizedModuleName = resolver.normalize(moduleName),
            ctx = this.get('ctx'),
            module = resolver.resolve(normalizedModuleName),
            registry = ctx.registry || ctx.container;
        if(!registry.registrations[normalizedModuleName]){
            registry.register(moduleName, module);
        }
        return module;
    },
    _registerModelsAndTransforms: function(){
        var entries = requirejs.entries,
            modelPrefix = this.get('modulePrefix') + '/models/',
            transformPrefix = this.get('modulePrefix') + '/transforms/',
            entry;
        for(entry in entries){
            if(entries.hasOwnProperty(entry)){
                if(entry.indexOf(modelPrefix) > -1){
                    this._registerDependency('model', entry.replace(modelPrefix, ''));
                }else if(entry.indexOf(transformPrefix) > -1){
                    this._registerDependency('transform', entry.replace(transformPrefix, ''));
                }
            }
        }
    },
    _makeRecordId: function(modelName){
        this.incrementProperty('numCreated');
        return modelName + this.get('numCreated') + '-' + Date.now();
    },
    _isSetup: Em.computed('ctx', 'store', function(){
        return this.get('ctx') && this.get('store');
    })
});

modelFactory = ModelFactory.create();

export default {
    setResolver: function(resolver){
        modelFactory.set('resolver', resolver);
    },
    setModulePrefix: function(prefix){
        modelFactory.set('modulePrefix', prefix);
    },
    setup: function(){
        if(!modelFactory.get('_isSetup')){
            modelFactory.setup();
        }
    },
    teardown: function(){
        modelFactory.teardown();
    },
    define: function(modelName, templateMap){
        templateMap = templateMap || {};
        modelFactory.defineTemplateMap(modelName, templateMap);
    },

    // context & store are unavailable during very first test, due to the the global 'beforeEach' loop is run prior to
    // the app being setup.  To get around this, calling setup once more when createRecord is called to make sure
    // that the model factory is completely setup.
    createRecord: function(modelName, typeParam, customId){
        this.setup();
        return modelFactory.createRecord(modelName, typeParam, customId);
    },
    createRecordList: function(modelName, count, typeParams, customIds){
        this.setup();
        return modelFactory.createRecordList(modelName, count, typeParams, customIds);
    }
};
<|endoftext|>


<commit_before>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// Define search commands. Depends on dialog.js or another
// implementation of the openDialog method.

// Replace works a little oddly -- it will do the replace on the next
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
// replace by making sure the match is no longer selected when hitting
// Ctrl-G.

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  "use strict";

  function searchOverlay(query, caseInsensitive) {
    if (typeof query == "string")
      query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
    else if (!query.global)
      query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");

    return {token: function(stream) {
      query.lastIndex = stream.pos;
      var match = query.exec(stream.string);
      if (match && match.index == stream.pos) {
        stream.pos += match[0].length;
        return "searching";
      } else if (match) {
        stream.pos = match.index;
      } else {
        stream.skipToEnd();
      }
    }};
  }

  function SearchState() {
    this.posFrom = this.posTo = this.lastQuery = this.query = null;
    this.overlay = null;
  }

  function getSearchState(cm) {
    return cm.state.search || (cm.state.search = new SearchState());
  }

  function queryCaseInsensitive(query) {
    return typeof query == "string" && query == query.toLowerCase();
  }

  function getSearchCursor(cm, query, pos) {
    // Heuristic: if the query string is all lowercase, do a case insensitive search.
    return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
  }

  function persistentDialog(cm, text, deflt, f) {
    cm.openDialog(text, f, {
      value: deflt,
      selectValueOnOpen: true,
      closeOnEnter: false,
      onClose: function() { clearSearch(cm); }
    });
  }

  function dialog(cm, text, shortText, deflt, f) {
    if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
    else f(prompt(shortText, deflt));
  }

  function confirmDialog(cm, text, shortText, fs) {
    if (cm.openConfirm) cm.openConfirm(text, fs);
    else if (confirm(shortText)) fs[0]();
  }

  function parseString(string) {
    return string.replace(/\\(.)/g, function(_, ch) {
      if (ch == "n") return "\n"
      if (ch == "r") return "\r"
      return ch
    })
  }

  function parseQuery(query) {
    var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
    if (isRE) {
      try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
      catch(e) {} // Not a regular expression after all, do a string search
    } else {
      query = parseString(query)
    }
    if (typeof query == "string" ? query == "" : query.test(""))
      query = /x^/;
    return query;
  }

  var queryDialog =
    'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> (Use /re/ syntax for regexp search)';

  function startSearch(cm, state, query) {
    state.queryText = query;
    state.query = parseQuery(query);
    cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
    state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
    cm.addOverlay(state.overlay);
    if (cm.showMatchesOnScrollbar) {
      if (state.annotate) { state.annotate.clear(); state.annotate = null; }
      state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
    }
  }

  function doSearch(cm, rev, persistent) {
    var state = getSearchState(cm);
    if (state.query) return findNext(cm, rev);
    var q = cm.getSelection() || state.lastQuery;
    if (persistent && cm.openDialog) {
      persistentDialog(cm, queryDialog, q, function(query, event) {
        CodeMirror.e_stop(event);
        if (!query) return;
        if (query != state.queryText) startSearch(cm, state, query);
        findNext(cm, event.shiftKey);
      });
    } else {
      dialog(cm, queryDialog, "Search for:", q, function(query) {
        if (query && !state.query) cm.operation(function() {
          startSearch(cm, state, query);
          state.posFrom = state.posTo = cm.getCursor();
          findNext(cm, rev);
        });
      });
    }
  }

  function findNext(cm, rev) {cm.operation(function() {
    var state = getSearchState(cm);
    var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
    if (!cursor.find(rev)) {
      cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
      if (!cursor.find(rev)) return;
    }
    cm.setSelection(cursor.from(), cursor.to());
    cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
    state.posFrom = cursor.from(); state.posTo = cursor.to();
  });}

  function clearSearch(cm) {cm.operation(function() {
    var state = getSearchState(cm);
    state.lastQuery = state.query;
    if (!state.query) return;
    state.query = state.queryText = null;
    cm.removeOverlay(state.overlay);
    if (state.annotate) { state.annotate.clear(); state.annotate = null; }
  });}

  var replaceQueryDialog =
    ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> (Use /re/ syntax for regexp search)';
  var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
  var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";

  function replaceAll(cm, query, text) {
    cm.operation(function() {
      for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
        if (typeof query != "string") {
          var match = cm.getRange(cursor.from(), cursor.to()).match(query);
          cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
        } else cursor.replace(text);
      }
    });
  }

  function replace(cm, all) {
    if (cm.getOption("readOnly")) return;
    var query = cm.getSelection() || getSearchState(cm).lastQuery;
    var dialogText = all ? "Replace all:" : "Replace:"
    dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
      if (!query) return;
      query = parseQuery(query);
      dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
        text = parseString(text)
        if (all) {
          replaceAll(cm, query, text)
        } else {
          clearSearch(cm);
          var cursor = getSearchCursor(cm, query, cm.getCursor());
          var advance = function() {
            var start = cursor.from(), match;
            if (!(match = cursor.findNext())) {
              cursor = getSearchCursor(cm, query);
              if (!(match = cursor.findNext()) ||
                  (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
            }
            cm.setSelection(cursor.from(), cursor.to());
            cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
            confirmDialog(cm, doReplaceConfirm, "Replace?",
                          [function() {doReplace(match);}, advance,
                           function() {replaceAll(cm, query, text)}]);
          };
          var doReplace = function(match) {
            cursor.replace(typeof query == "string" ? text :
                           text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
            advance();
          };
          advance();
        }
      });
    });
  }

  CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
  CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
  CodeMirror.commands.findNext = doSearch;
  CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
  CodeMirror.commands.clearSearch = clearSearch;
  CodeMirror.commands.replace = replace;
  CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
});
<commit_msg>[search addon] Make persistent dialog transparent when hiding current match<commit_after>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// Define search commands. Depends on dialog.js or another
// implementation of the openDialog method.

// Replace works a little oddly -- it will do the replace on the next
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
// replace by making sure the match is no longer selected when hitting
// Ctrl-G.

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  "use strict";

  function searchOverlay(query, caseInsensitive) {
    if (typeof query == "string")
      query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
    else if (!query.global)
      query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");

    return {token: function(stream) {
      query.lastIndex = stream.pos;
      var match = query.exec(stream.string);
      if (match && match.index == stream.pos) {
        stream.pos += match[0].length;
        return "searching";
      } else if (match) {
        stream.pos = match.index;
      } else {
        stream.skipToEnd();
      }
    }};
  }

  function SearchState() {
    this.posFrom = this.posTo = this.lastQuery = this.query = null;
    this.overlay = null;
  }

  function getSearchState(cm) {
    return cm.state.search || (cm.state.search = new SearchState());
  }

  function queryCaseInsensitive(query) {
    return typeof query == "string" && query == query.toLowerCase();
  }

  function getSearchCursor(cm, query, pos) {
    // Heuristic: if the query string is all lowercase, do a case insensitive search.
    return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
  }

  function persistentDialog(cm, text, deflt, f) {
    cm.openDialog(text, f, {
      value: deflt,
      selectValueOnOpen: true,
      closeOnEnter: false,
      onClose: function() { clearSearch(cm); }
    });
  }

  function dialog(cm, text, shortText, deflt, f) {
    if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
    else f(prompt(shortText, deflt));
  }

  function confirmDialog(cm, text, shortText, fs) {
    if (cm.openConfirm) cm.openConfirm(text, fs);
    else if (confirm(shortText)) fs[0]();
  }

  function parseString(string) {
    return string.replace(/\\(.)/g, function(_, ch) {
      if (ch == "n") return "\n"
      if (ch == "r") return "\r"
      return ch
    })
  }

  function parseQuery(query) {
    var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
    if (isRE) {
      try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
      catch(e) {} // Not a regular expression after all, do a string search
    } else {
      query = parseString(query)
    }
    if (typeof query == "string" ? query == "" : query.test(""))
      query = /x^/;
    return query;
  }

  var queryDialog =
    'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> (Use /re/ syntax for regexp search)';

  function startSearch(cm, state, query) {
    state.queryText = query;
    state.query = parseQuery(query);
    cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
    state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
    cm.addOverlay(state.overlay);
    if (cm.showMatchesOnScrollbar) {
      if (state.annotate) { state.annotate.clear(); state.annotate = null; }
      state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
    }
  }

  function doSearch(cm, rev, persistent) {
    var state = getSearchState(cm);
    if (state.query) return findNext(cm, rev);
    var q = cm.getSelection() || state.lastQuery;
    if (persistent && cm.openDialog) {
      var hiding = null
      persistentDialog(cm, queryDialog, q, function(query, event) {
        CodeMirror.e_stop(event);
        if (!query) return;
        if (query != state.queryText) startSearch(cm, state, query);
        if (hiding) hiding.style.opacity = 1
        findNext(cm, event.shiftKey, function(_, to) {
          var dialog
          if (to.line < 3 && document.querySelector &&
              (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
              dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
            (hiding = dialog).style.opacity = .4
        })
      });
    } else {
      dialog(cm, queryDialog, "Search for:", q, function(query) {
        if (query && !state.query) cm.operation(function() {
          startSearch(cm, state, query);
          state.posFrom = state.posTo = cm.getCursor();
          findNext(cm, rev);
        });
      });
    }
  }

  function findNext(cm, rev, callback) {cm.operation(function() {
    var state = getSearchState(cm);
    var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
    if (!cursor.find(rev)) {
      cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
      if (!cursor.find(rev)) return;
    }
    cm.setSelection(cursor.from(), cursor.to());
    cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
    state.posFrom = cursor.from(); state.posTo = cursor.to();
    if (callback) callback(cursor.from(), cursor.to())
  });}

  function clearSearch(cm) {cm.operation(function() {
    var state = getSearchState(cm);
    state.lastQuery = state.query;
    if (!state.query) return;
    state.query = state.queryText = null;
    cm.removeOverlay(state.overlay);
    if (state.annotate) { state.annotate.clear(); state.annotate = null; }
  });}

  var replaceQueryDialog =
    ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> (Use /re/ syntax for regexp search)';
  var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
  var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";

  function replaceAll(cm, query, text) {
    cm.operation(function() {
      for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
        if (typeof query != "string") {
          var match = cm.getRange(cursor.from(), cursor.to()).match(query);
          cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
        } else cursor.replace(text);
      }
    });
  }

  function replace(cm, all) {
    if (cm.getOption("readOnly")) return;
    var query = cm.getSelection() || getSearchState(cm).lastQuery;
    var dialogText = all ? "Replace all:" : "Replace:"
    dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
      if (!query) return;
      query = parseQuery(query);
      dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
        text = parseString(text)
        if (all) {
          replaceAll(cm, query, text)
        } else {
          clearSearch(cm);
          var cursor = getSearchCursor(cm, query, cm.getCursor());
          var advance = function() {
            var start = cursor.from(), match;
            if (!(match = cursor.findNext())) {
              cursor = getSearchCursor(cm, query);
              if (!(match = cursor.findNext()) ||
                  (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
            }
            cm.setSelection(cursor.from(), cursor.to());
            cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
            confirmDialog(cm, doReplaceConfirm, "Replace?",
                          [function() {doReplace(match);}, advance,
                           function() {replaceAll(cm, query, text)}]);
          };
          var doReplace = function(match) {
            cursor.replace(typeof query == "string" ? text :
                           text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
            advance();
          };
          advance();
        }
      });
    });
  }

  CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
  CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
  CodeMirror.commands.findNext = doSearch;
  CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
  CodeMirror.commands.clearSearch = clearSearch;
  CodeMirror.commands.replace = replace;
  CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
});
<|endoftext|>


<commit_before>import { isBlank } from '@ember/utils';
import { assert } from '@ember/debug';
import {
  resolve,
  reject,
  hash
} from 'rsvp';
import { computed } from '@ember/object';
import Service from '@ember/service';
import i18next from 'i18next';
import i18nextXHRBackend from 'i18next-xhr-backend';

import config from 'ember-i18next/configuration';

/**
 * A service that exposes functionality from i18next.
 */
const I18nService = Service.extend({
  i18next: null,
  isInitialized: false,

  _locale: null,
  _preInitActions: null,
  _postInitActions: null,

  _errors: null,

  init() {
    this._super(...arguments);
    this.set('i18next', i18next);
    this.set('_preInitActions', {});
    this.set('_postInitActions', {});
  },

  /**
   * The current locale. This is a settable computed property; when set, the locale
   * will be changed using `i18next.setLng()` and registered pre- and post-init
   * actions will run. Finally, the locale will change, triggering a refresh of
   * localized text.
   */
  locale: computed('i18next', '_locale', {
    get() {
      return this.get('_locale');
    },
    set(key, value) {
      const lang = value;

      if (this.get('isInitialized')) {
        this._changeLocale(lang)
          .then(lang => this.set('_locale', lang));
      } else {
        this.set('_locale', lang);
      }

      return lang;
    }
  }),

  /**
   * Initializes the i18next library with configuration from the environment.
   *
   * @return {Promise} - a promise that resolves with the i18next object when
   *   i18next has finished initializing.
   */
  initLibraryAsync() {
    const i18next = this.get('i18next');
    const options = config.i18nextOptions || {};

    return this._runPreInitActions()
      .then(() => this._initLibrary())
      .then(() => this._runPostInitActions())
      .then(() => {
        this.set('_locale', i18next.language);
        this.set('isInitialized', true);
        return resolve();
      }).catch(reason => {
        // eslint-disable-next-line no-console
        console.warn(`A promise in the i18next init chain rejected with reason: ${reason}`);
        if (options.rejectError) {
          return reject(reason);
        }
      });
  },

  /**
   * Registers an action to execute before initializing i18next. Before initializing
   * the library or setting the language (which reinitializes the library), each of
   * the registered actions will be executed.
   *
   * If any pre-init actions return a promise, the service will wait until all the
   * promises have settled before initializing i18next.
   *
   * @param {String|Object} key -  the key to use to look up the action. May not be
   *   blank.
   * @param {Function} fn - a zero-argument callback function. Return a promise if
   *   the operation needs to complete before the i18next is initialized.
   */
  registerPreInitAction(key, fn) {
    assert('Pre-init action key may not be blank', !isBlank(key));
    assert('A pre-init action must be a function', typeof fn === 'function');
    this.get('_preInitActions')[key] = fn;
  },

  /**
   * Removes an action from the set of actions executed before initializing i18next.
   *
   * @param {String|Object} key - the key to use to look up the action to remove.
   *   May not be blank.
   */
  unregisterPreInitAction(key) {
    assert('Action key may not be blank', !isBlank(key));
    const preInitActions = this.get('_preInitActions');

    delete preInitActions[key];
  },

  /**
   * Registers an action to execute after initializing i18next. After initializing
   * the library or setting the language (which reinitializes the library), each of
   * the registered actions will be executed.
   *
   * If any post-init actions return a promise, the service will wait until all the
   * promises have settled before triggering a UI refresh.
   *
   * @param {String|Object} key -  the key to use to look up the action. May not be
   *   blank.
   * @param {Function} fn - a zero-argument callback function. Return a promise if
   *   the operation needs to complete before the the UI is refreshed.
   */
  registerPostInitAction(name, fn) {
    assert('Pre-init action name may not be blank', !isBlank(name));
    assert('A post-init action must be a function', typeof fn === 'function');
    this.get('_postInitActions')[name] = fn;
  },

  /**
   * Removes an action from the set of actions executed after initializing i18next.
   *
   * @param {String|Object} key - the key to use to look up the action to remove.
   *   May not be blank.
   */
  unregisterPostInitAction(key) {
    assert('Action key may not be blank', !isBlank(key));
    const postInitActions = this.get('_postInitActions');

    delete postInitActions[key];
  },

  /**
   * Changes the locale, ensuring that pre- and post-init actions run.
   *
   * @param {String} lang - locale code to set.
   *
   * @return {Promise} a promise that resolves with the language code when complete.
   */
  _changeLocale(lang) {
    const i18next = this.get('i18next');

    if (i18next && lang && i18next.language === lang) {
      return resolve(lang);
    }

    const oldLang = this._locale;
    return this._runPreInitActions(lang)
      .then(() => this._setLng(lang))
      .then(() => this._runPostInitActions(oldLang))
      .then(() => resolve(lang))
      .catch(reason => {
        // eslint-disable-next-line no-console
        console.warn(`A promise in the locale change path rejected with reason: ${reason}`);
      });
  },

  /**
   * Forwarded to `i18next.t()`.
   *
   * @param {String} path - an string that specifies the translation lookup key.
   *   Required.
   * @param {Object} values - an object that specifies values to substitute into
   *   the translation for the specified path. Optional.
   *
   * @return Localized text.
   */
  t(path, values) {
    const i18next = this.get('i18next');
    return i18next.t(path, values);
  },

  /**
   * Forwarded to `i18next.addResourceBundle()`.
   */
  addResourceBundle(lang, ns, resources, deep, overwrite) {
    return this.get('i18next').addResourceBundle(lang, ns, resources, deep, overwrite);
  },

  /**
   * Forwarded to `i18next.hasResourceBundle()`.
   */
  hasResourceBundle(lang, ns) {
    return this.get('i18next').hasResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.getResourceBundle()`.
   */
  getResourceBundle(lang, ns) {
    return this.get('i18next').getResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.removeResourceBundle()`.
   */
  removeResourceBundle(lang, ns) {
    return this.get('i18next').removeResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.addResource()`.
   */
  addResource(lang, ns, key, value, options) {
    return this.get('i18next').addResource(lang, ns, key, value, options);
  },

  /**
   * Forwarded to `i18next.addResources()`.
   */
  addResources(lang, ns, resources) {
    return this.get('i18next').addResources(lang, ns, resources);
  },

  /**
   * Forwarded to `i18next.loadNamespaces()`.
   */
  loadNamespaces(namespaces, callback) {
    return this.get('i18next').loadNamespaces(namespaces, callback);
  },

  /**
   * Forwarded to `i18next.setDefaultNamespace()`.
   */
  setDefaultNamespace(ns) {
    return this.get('i18next').setDefaultNamespace(ns);
  },

  /**
   * Alias for `t()`.
   */
  translate(key, values) {
    return this.t(key, values);
  },

  /**
   * Forwarded to `i18next.exists()`.
   */
  exists(key, options) {
    return this.get('i18next').exists(key, options);
  },

  /**
   * Gets i18next's `pluralExtensions` property.
   */
  pluralExtensions: computed('i18next', function () {
    return this.get('i18next').pluralExtensions;
  }),

  /**
   * Forwarded to `i18next.addPostProcessor()`.
   */
  addPostProcessor(name, fn) {
    return this.get('i18next').addPostProcessor(name, fn);
  },

  /**
   * Forwarded to `i18next.applyReplacement()`.
   */
  applyReplacement(str, replacementHash, nestedKey, options) {
    return this.get('i18next').applyReplacement(str, replacementHash, nestedKey, options);
  },

  _initLibrary() {
    const i18next = this.get('i18next');
    const options = config.i18nextOptions || {};

    let errors;

    //
    //  TODO:  Adding i18nextXHRBackend by default so that translation
    //         files can be loaded.
    //         How do we extend this so that other plugins can be added
    //         dynamically?
    //
    return i18next
      .use(i18nextXHRBackend)
      .init(options, (err) => {
        if (err) errors = err;
      })
      .then(() => {
        if (errors) {
          return reject(errors);
        }
        else {
          return resolve(i18next);
        }
      });
  },

  _setLng(locale) {
    const i18next = this.get('i18next');
    return i18next.changeLanguage(locale)
      .then(() => resolve(locale));
  },

  _getActionCallHash(actions, lang) {
    const actionsCallHash = {};

    Object.keys(actions).forEach(key => {
      actionsCallHash[key] = actions[key].call(undefined, lang);
    });

    return actionsCallHash;
  },

  _runPreInitActions(newLang) {
    const _preInitActions = this.get('_preInitActions');
    const actionCalls = this._getActionCallHash(_preInitActions, newLang);

    return hash(actionCalls, 'ember-i18next: pre init actions');
  },

  _runPostInitActions(oldLang) {
    const _postInitActions = this.get('_postInitActions');
    const actionCalls = this._getActionCallHash(_postInitActions, oldLang);

    return hash(actionCalls, 'ember-i18next: post init actions');
  }
});

export default I18nService;
<commit_msg>Remove useless `_errors` var<commit_after>import { isBlank } from '@ember/utils';
import { assert } from '@ember/debug';
import {
  resolve,
  reject,
  hash
} from 'rsvp';
import { computed } from '@ember/object';
import Service from '@ember/service';
import i18next from 'i18next';
import i18nextXHRBackend from 'i18next-xhr-backend';

import config from 'ember-i18next/configuration';

/**
 * A service that exposes functionality from i18next.
 */
const I18nService = Service.extend({
  i18next: null,
  isInitialized: false,

  _locale: null,
  _preInitActions: null,
  _postInitActions: null,

  init() {
    this._super(...arguments);
    this.set('i18next', i18next);
    this.set('_preInitActions', {});
    this.set('_postInitActions', {});
  },

  /**
   * The current locale. This is a settable computed property; when set, the locale
   * will be changed using `i18next.setLng()` and registered pre- and post-init
   * actions will run. Finally, the locale will change, triggering a refresh of
   * localized text.
   */
  locale: computed('i18next', '_locale', {
    get() {
      return this.get('_locale');
    },
    set(key, value) {
      const lang = value;

      if (this.get('isInitialized')) {
        this._changeLocale(lang)
          .then(lang => this.set('_locale', lang));
      } else {
        this.set('_locale', lang);
      }

      return lang;
    }
  }),

  /**
   * Initializes the i18next library with configuration from the environment.
   *
   * @return {Promise} - a promise that resolves with the i18next object when
   *   i18next has finished initializing.
   */
  initLibraryAsync() {
    const i18next = this.get('i18next');
    const options = config.i18nextOptions || {};

    return this._runPreInitActions()
      .then(() => this._initLibrary())
      .then(() => this._runPostInitActions())
      .then(() => {
        this.set('_locale', i18next.language);
        this.set('isInitialized', true);
        return resolve();
      }).catch(reason => {
        // eslint-disable-next-line no-console
        console.warn(`A promise in the i18next init chain rejected with reason: ${reason}`);
        if (options.rejectError) {
          return reject(reason);
        }
      });
  },

  /**
   * Registers an action to execute before initializing i18next. Before initializing
   * the library or setting the language (which reinitializes the library), each of
   * the registered actions will be executed.
   *
   * If any pre-init actions return a promise, the service will wait until all the
   * promises have settled before initializing i18next.
   *
   * @param {String|Object} key -  the key to use to look up the action. May not be
   *   blank.
   * @param {Function} fn - a zero-argument callback function. Return a promise if
   *   the operation needs to complete before the i18next is initialized.
   */
  registerPreInitAction(key, fn) {
    assert('Pre-init action key may not be blank', !isBlank(key));
    assert('A pre-init action must be a function', typeof fn === 'function');
    this.get('_preInitActions')[key] = fn;
  },

  /**
   * Removes an action from the set of actions executed before initializing i18next.
   *
   * @param {String|Object} key - the key to use to look up the action to remove.
   *   May not be blank.
   */
  unregisterPreInitAction(key) {
    assert('Action key may not be blank', !isBlank(key));
    const preInitActions = this.get('_preInitActions');

    delete preInitActions[key];
  },

  /**
   * Registers an action to execute after initializing i18next. After initializing
   * the library or setting the language (which reinitializes the library), each of
   * the registered actions will be executed.
   *
   * If any post-init actions return a promise, the service will wait until all the
   * promises have settled before triggering a UI refresh.
   *
   * @param {String|Object} key -  the key to use to look up the action. May not be
   *   blank.
   * @param {Function} fn - a zero-argument callback function. Return a promise if
   *   the operation needs to complete before the the UI is refreshed.
   */
  registerPostInitAction(name, fn) {
    assert('Pre-init action name may not be blank', !isBlank(name));
    assert('A post-init action must be a function', typeof fn === 'function');
    this.get('_postInitActions')[name] = fn;
  },

  /**
   * Removes an action from the set of actions executed after initializing i18next.
   *
   * @param {String|Object} key - the key to use to look up the action to remove.
   *   May not be blank.
   */
  unregisterPostInitAction(key) {
    assert('Action key may not be blank', !isBlank(key));
    const postInitActions = this.get('_postInitActions');

    delete postInitActions[key];
  },

  /**
   * Changes the locale, ensuring that pre- and post-init actions run.
   *
   * @param {String} lang - locale code to set.
   *
   * @return {Promise} a promise that resolves with the language code when complete.
   */
  _changeLocale(lang) {
    const i18next = this.get('i18next');

    if (i18next && lang && i18next.language === lang) {
      return resolve(lang);
    }

    const oldLang = this._locale;
    return this._runPreInitActions(lang)
      .then(() => this._setLng(lang))
      .then(() => this._runPostInitActions(oldLang))
      .then(() => resolve(lang))
      .catch(reason => {
        // eslint-disable-next-line no-console
        console.warn(`A promise in the locale change path rejected with reason: ${reason}`);
      });
  },

  /**
   * Forwarded to `i18next.t()`.
   *
   * @param {String} path - an string that specifies the translation lookup key.
   *   Required.
   * @param {Object} values - an object that specifies values to substitute into
   *   the translation for the specified path. Optional.
   *
   * @return Localized text.
   */
  t(path, values) {
    const i18next = this.get('i18next');
    return i18next.t(path, values);
  },

  /**
   * Forwarded to `i18next.addResourceBundle()`.
   */
  addResourceBundle(lang, ns, resources, deep, overwrite) {
    return this.get('i18next').addResourceBundle(lang, ns, resources, deep, overwrite);
  },

  /**
   * Forwarded to `i18next.hasResourceBundle()`.
   */
  hasResourceBundle(lang, ns) {
    return this.get('i18next').hasResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.getResourceBundle()`.
   */
  getResourceBundle(lang, ns) {
    return this.get('i18next').getResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.removeResourceBundle()`.
   */
  removeResourceBundle(lang, ns) {
    return this.get('i18next').removeResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.addResource()`.
   */
  addResource(lang, ns, key, value, options) {
    return this.get('i18next').addResource(lang, ns, key, value, options);
  },

  /**
   * Forwarded to `i18next.addResources()`.
   */
  addResources(lang, ns, resources) {
    return this.get('i18next').addResources(lang, ns, resources);
  },

  /**
   * Forwarded to `i18next.loadNamespaces()`.
   */
  loadNamespaces(namespaces, callback) {
    return this.get('i18next').loadNamespaces(namespaces, callback);
  },

  /**
   * Forwarded to `i18next.setDefaultNamespace()`.
   */
  setDefaultNamespace(ns) {
    return this.get('i18next').setDefaultNamespace(ns);
  },

  /**
   * Alias for `t()`.
   */
  translate(key, values) {
    return this.t(key, values);
  },

  /**
   * Forwarded to `i18next.exists()`.
   */
  exists(key, options) {
    return this.get('i18next').exists(key, options);
  },

  /**
   * Gets i18next's `pluralExtensions` property.
   */
  pluralExtensions: computed('i18next', function () {
    return this.get('i18next').pluralExtensions;
  }),

  /**
   * Forwarded to `i18next.addPostProcessor()`.
   */
  addPostProcessor(name, fn) {
    return this.get('i18next').addPostProcessor(name, fn);
  },

  /**
   * Forwarded to `i18next.applyReplacement()`.
   */
  applyReplacement(str, replacementHash, nestedKey, options) {
    return this.get('i18next').applyReplacement(str, replacementHash, nestedKey, options);
  },

  _initLibrary() {
    const i18next = this.get('i18next');
    const options = config.i18nextOptions || {};

    let errors;

    //
    //  TODO:  Adding i18nextXHRBackend by default so that translation
    //         files can be loaded.
    //         How do we extend this so that other plugins can be added
    //         dynamically?
    //
    return i18next
      .use(i18nextXHRBackend)
      .init(options, (err) => {
        if (err) errors = err;
      })
      .then(() => {
        if (errors) {
          return reject(errors);
        }
        else {
          return resolve(i18next);
        }
      });
  },

  _setLng(locale) {
    const i18next = this.get('i18next');
    return i18next.changeLanguage(locale)
      .then(() => resolve(locale));
  },

  _getActionCallHash(actions, lang) {
    const actionsCallHash = {};

    Object.keys(actions).forEach(key => {
      actionsCallHash[key] = actions[key].call(undefined, lang);
    });

    return actionsCallHash;
  },

  _runPreInitActions(newLang) {
    const _preInitActions = this.get('_preInitActions');
    const actionCalls = this._getActionCallHash(_preInitActions, newLang);

    return hash(actionCalls, 'ember-i18next: pre init actions');
  },

  _runPostInitActions(oldLang) {
    const _postInitActions = this.get('_postInitActions');
    const actionCalls = this._getActionCallHash(_postInitActions, oldLang);

    return hash(actionCalls, 'ember-i18next: post init actions');
  }
});

export default I18nService;
<|endoftext|>


<commit_before>var keystone = require('../../../');
var Types = keystone.Field.Types;

module.exports = {

	upload: function (req, res) {
		var knox = require('knox');

		if (!keystone.security.csrf.validate(req, req.body.authenticity_token)) {
			return res.status(403).send({ error: { message: 'invalid csrf' } });
		}

		if (req.files && req.files.file) {

			var s3Config = keystone.get('s3 config');

			var file = req.files.file;
			var path = s3Config.s3path ? s3Config.s3path + '/' : '';

			var headers = Types.S3File.prototype.generateHeaders.call({ s3config: s3Config, options: {} }, null, file);

			var s3Client = knox.createClient(s3Config);

			s3Client.putFile(file.path, path + file.name, headers, function (err, s3Response) {
				var sendResult = function () {
					if (err) {
						return res.send({ error: { message: err.message } });
					}

					if (s3Response) {
						if (s3Response.statusCode !== 200) {
							return res.send({ error: { message: 'Amazon returned Http Code: ' + s3Response.statusCode } });
						} else {
							return res.send({ image: { url: 'https://s3.amazonaws.com/' + s3Config.bucket + '/' + file.name } });
						}
					}
				};

				res.format({
					html: sendResult,
					json: sendResult,
				});
			});

		} else {
			res.json({ error: { message: 'No image selected' } });
		}
	},
};
<commit_msg>Add Region to S3 Image URL<commit_after>var keystone = require('../../../');
var Types = keystone.Field.Types;

module.exports = {

	upload: function (req, res) {
		var knox = require('knox');

		if (!keystone.security.csrf.validate(req, req.body.authenticity_token)) {
			return res.status(403).send({ error: { message: 'invalid csrf' } });
		}

		if (req.files && req.files.file) {

			var s3Config = keystone.get('s3 config');

			var file = req.files.file;
			var path = s3Config.s3path ? s3Config.s3path + '/' : '';

			var headers = Types.S3File.prototype.generateHeaders.call({ s3config: s3Config, options: {} }, null, file);

			var s3Client = knox.createClient(s3Config);

			s3Client.putFile(file.path, path + file.name, headers, function (err, s3Response) {
				var sendResult = function () {
					if (err) {
						return res.send({ error: { message: err.message } });
					}

					if (s3Response) {
						if (s3Response.statusCode !== 200) {
							return res.send({ error: { message: 'Amazon returned Http Code: ' + s3Response.statusCode } });
						} else {
							var region = 's3';
							if (s3Config.region && s3Config.region !== 'us-east-1') {
								region = 's3-' + s3Config.region;
							}
							return res.send({ image: { url: 'https://' + region + '.amazonaws.com/' + s3Config.bucket + '/' + file.name } });
						}
					}
				};

				res.format({
					html: sendResult,
					json: sendResult,
				});
			});

		} else {
			res.json({ error: { message: 'No image selected' } });
		}
	},
};
<|endoftext|>


<commit_before>/*
 *
 * @author    Gabriel de Maeztu <gabriel.maeztu@gmail.com>
 * @version   2.0.0
 * @license   MIT license
 * @see       http://github.com/merqurio/jupyter_themes
 * @copyright 2015-2016, Gabriel de Maeztu, http://merqur.io
 *
 */

 define([
   'require',
   'jquery',
   'base/js/namespace'
 ], function(require, $, Jupyter) {
   'use strict';

    var themes = {
      "Default": null,
      "3024-day": "/static/components/codemirror/theme/3024-day.css",
      "3024-night": "/static/components/codemirror/theme/3024-night.css",
      "ambiance-mobile": "/static/components/codemirror/theme/ambiance-mobile.css",
      "ambiance": "/static/components/codemirror/theme/ambiance.css",
      "base16-dark": "/static/components/codemirror/theme/base16-dark.css",
      "base16-light": "/static/components/codemirror/theme/base16-light.css",
      "blackboard": "/static/components/codemirror/theme/blackboard.css",
      "cobalt": "/static/components/codemirror/theme/cobalt.css",
      "colorforth": "/static/components/codemirror/theme/colorforth.css",
      "dracula": "/static/components/codemirror/theme/dracula.css",
      "eclipse": "/static/components/codemirror/theme/eclipse.css",
      "elegant": "/static/components/codemirror/theme/elegant.css",
      "erlang-dark": "/static/components/codemirror/theme/erlang-dark.css",
      "icecoder": "/static/components/codemirror/theme/icecoder.css",
      "lesser-dark": "/static/components/codemirror/theme/lesser-dark.css",
      "liquibyte": "/static/components/codemirror/theme/liquibyte.css",
      "material": "/static/components/codemirror/theme/material.css",
      "mbo": "/static/components/codemirror/theme/mbo.css",
      "mdn-like": "/static/components/codemirror/theme/mdn-like.css",
      "midnight": "/static/components/codemirror/theme/midnight.css",
      "monokai": "/static/components/codemirror/theme/monokai.css",
      "neat": "/static/components/codemirror/theme/neat.css",
      "neo": "/static/components/codemirror/theme/neo.css",
      "night": "/static/components/codemirror/theme/night.css",
      "paraiso-dark": "/static/components/codemirror/theme/paraiso-dark.css",
      "paraiso-light": "/static/components/codemirror/theme/paraiso-light.css",
      "pastel-on-dark": "/static/components/codemirror/theme/pastel-on-dark.css",
      "rubyblue": "/static/components/codemirror/theme/rubyblue.css",
      "seti": "/static/components/codemirror/theme/seti.css",
      "solarized": "/static/components/codemirror/theme/solarized.css",
      "the-matrix": "/static/components/codemirror/theme/the-matrix.css",
      "tomorrow-night-bright": "/static/components/codemirror/theme/tomorrow-night-bright.css",
      "tomorrow-night-eighties": "/static/components/codemirror/theme/tomorrow-night-eighties.css",
      "ttcn": "/static/components/codemirror/theme/ttcn.css",
      "twilight": "/static/components/codemirror/theme/twilight.css",
      "vibrant-ink": "/static/components/codemirror/theme/vibrant-ink.css",
      "xq-dark": "/static/components/codemirror/theme/xq-dark.css",
      "xq-light": "/static/components/codemirror/theme/xq-light.css",
      "yeti": "/static/components/codemirror/theme/yeti.css",
      "zenburn": "/static/components/codemirror/theme/zenburn.css"
    };

    var fonts = {
      "Default": {
        "css": "monospace",
        "url": null
      },
      "Hack": {
        "css": "Hack",
        "url": "//cdn.jsdelivr.net/font-hack/2.019/css/hack-extended.min.css"
      },
      "Inconsolata": {
        "css": "Inconsolata",
        "url": "//fonts.googleapis.com/css?family=Inconsolata"
      },
      "Source Code Pro": {
        "css": "Source Code Pro",
        "url": "//fonts.googleapis.com/css?family=Source+Code+Pro"
      },
      "Roboto Mono": {
        "css": "Roboto Mono",
        "url": "//fonts.googleapis.com/css?family=Roboto+Mono"
      },
      "Droid Sans Mono": {
        "css": "Droid Sans Mono",
        "url": "//fonts.googleapis.com/css?family=Droid+Sans+Mono"
      },
      "Ubuntu Mono": {
        "css": "Ubuntu Mono",
        "url": "//fonts.googleapis.com/css?family=Ubuntu+Mono"
      },
      "PT Mono": {
        "css": "PT Mono",
        "url": "//fonts.googleapis.com/css?family=PT+Mono"
      },
      "Fira Mono":{
        "css": "Fira Mono",
        "url": "//fonts.googleapis.com/css?family=Fira+Mono"
      }
    };

    var CELLS, CODE_CELL;

    function add_to_toolbar(current_theme) {

        var cell_menu = $('#cell_menu'),
          divider = $('<li/>').addClass('divider'),
          theme_btn = $('<li/>').addClass('dropdown-submenu'),
          theme_txt = $('<a/>').text('Code Syntax Theme').attr('href', '#'),
          theme_list = $('<ul/>').addClass('dropdown-menu').attr('id', 'theme_select'),
          font_btn = $('<li/>').addClass('dropdown-submenu'),
          font_txt = $('<a/>').text('Code Font').attr('href', '#'),
          font_list = $('<ul/>').addClass('dropdown-menu').attr('id', 'font_select'),
          line_btn = $('<li/>'),
          line_txt = $('<a/>').text('Code Line Numbers').attr('href', '#');

        // Add label to the toolbar
        cell_menu
          .append(divider)
          .append(theme_btn.append(theme_txt).append(theme_list))
          .append(font_btn.append(font_txt).append(font_list))
          .append(line_btn.append(line_txt));

        // Add themes to the selector
        for (var key in themes){
            theme_list.append(
              $('<li/>').append(
                $('<a/>').text(key)
                  .attr('href', '#')
                  .attr('data-value', key)
              )
            );
        }

        theme_list.click(
          function(e){
            e.preventDefault;
            if (e.target.tagName === "A"){
                theme_toggle($(e.target).data("value"));
            }
          }
        );

        // Add fonts to the selector
        for (var key in fonts){
            font_list.append(
              $('<li/>').append(
                $('<a/>').text(key)
                  .attr('href', '#')
                  .attr('data-key', key)
                  .attr('data-css', fonts[key].css)
                  .attr('data-url', fonts[key].url)
              )
            );
        }

        font_list.click(
          function(e){
            e.preventDefault;
            if (e.target.tagName === "A"){
                font_toggle(
                  $(e.target).data("key"),
                  $(e.target).data("css"),
                  $(e.target).data("url")
                );
            }
          }
        );

        // Toggle line numbers
        line_txt.click(
          function(e){
            e.preventDefault;

            var opt = CODE_CELL.config.data.CodeCell.cm_config.lineNumbers;
            var config = CODE_CELL.config;
            var patch = {
              CodeCell:{
                cm_config:{
                  lineNumbers: !opt
                }
              }
            }
            config.update(patch);

            for (var i = 0; i < CELLS.length; i++){
              if(CELLS[i].cell_type == "code"){
                CELLS[i].code_mirror.setOption('lineNumbers', !opt);
              }
            }

          }
        );

    }

    function load_css(theme) {
        // Create a link element to attach the styles
        var link = document.createElement("link");
        link.type = "text/css";
        link.rel = "stylesheet";
        link.href = require.toUrl(themes[theme]);
        link.id = theme + "-css";
        document.getElementsByTagName("head")[0].appendChild(link);
    }

    function load_font(href) {
      // Create a link element to attach the font
      var link = document.createElement("link");
      link.type = "text/css";
      link.rel = "stylesheet";
      link.href = href;
      document.getElementsByTagName("head")[0].appendChild(link);
    }

    function css_toggle(font) {

      var style = document.getElementById("font-css");

      if (!style){
        // Create a style element
        var style = document.createElement("style");
        style.type = "text/css";
        style.id = "font-css"
        document.head.appendChild(style);
      }

      style.innerText = ".CodeMirror {font-family: z;}".replace("z", font);

    }

    function theme_toggle(new_theme) {

      new_theme = (new_theme === "Default")? "ipython" : new_theme;

      if(new_theme !== "ipython") load_css(new_theme);

      var config = CODE_CELL.config;
      var patch = {
        CodeCell:{
          cm_config:{
            theme: new_theme
          }
        }
      }
      config.update(patch);

      for (var i = 0; i < CELLS.length; i++){
        if(CELLS[i].cell_type == "code"){
          CELLS[i].code_mirror.setOption('theme', new_theme);
        }
      }

    }

    function font_toggle(key, css, url) {

      var config = CODE_CELL.config;
      var patch = {
        CodeCell:{
          cm_config:{
            font_family: key
          }
        }
      }
      config.update(patch);

      if (key !== "default") {
        load_font(url);
      }

      css_toggle(css);

    }

    function load_cells() {

        CELLS = Jupyter.notebook.get_cells();

        for (var i = 0; i < CELLS.length; i++){
          if(CELLS[i].cell_type == "code"){
            CODE_CELL = CELLS[i];
            break;
          }
        }

        try {
          var theme = CODE_CELL.config.data.CodeCell.cm_config.theme;
          var key = CODE_CELL.config.data.CodeCell.cm_config.font_family;

          load_css(theme);

          if (key !== "default") {
            load_font(fonts[key].url);
            css_toggle(fonts[key].css);
          }
        }
        catch(error) {
          console.log(error);
        }

        add_to_toolbar();
    }

    function load_ipython_extension() {

        CELLS = Jupyter.notebook.get_cells();

        if (CELLS.length < 1) {
            setTimeout(load_cells(), 2000)
        }
        else {
            load_cells()
        }

    }

    return { load_ipython_extension: load_ipython_extension };

});
<commit_msg>Update for laaaaaaaarge Jupyter Notebooks<commit_after>/*
 *
 * @author    Gabriel de Maeztu <gabriel.maeztu@gmail.com>
 * @version   2.0.0
 * @license   MIT license
 * @see       http://github.com/merqurio/jupyter_themes
 * @copyright 2015-2016, Gabriel de Maeztu, http://merqur.io
 *
 */

 define([
   'require',
   'jquery',
   'base/js/namespace'
 ], function(require, $, Jupyter) {
   'use strict';

    var themes = {
      "Default": null,
      "3024-day": "/static/components/codemirror/theme/3024-day.css",
      "3024-night": "/static/components/codemirror/theme/3024-night.css",
      "ambiance-mobile": "/static/components/codemirror/theme/ambiance-mobile.css",
      "ambiance": "/static/components/codemirror/theme/ambiance.css",
      "base16-dark": "/static/components/codemirror/theme/base16-dark.css",
      "base16-light": "/static/components/codemirror/theme/base16-light.css",
      "blackboard": "/static/components/codemirror/theme/blackboard.css",
      "cobalt": "/static/components/codemirror/theme/cobalt.css",
      "colorforth": "/static/components/codemirror/theme/colorforth.css",
      "dracula": "/static/components/codemirror/theme/dracula.css",
      "eclipse": "/static/components/codemirror/theme/eclipse.css",
      "elegant": "/static/components/codemirror/theme/elegant.css",
      "erlang-dark": "/static/components/codemirror/theme/erlang-dark.css",
      "icecoder": "/static/components/codemirror/theme/icecoder.css",
      "lesser-dark": "/static/components/codemirror/theme/lesser-dark.css",
      "liquibyte": "/static/components/codemirror/theme/liquibyte.css",
      "material": "/static/components/codemirror/theme/material.css",
      "mbo": "/static/components/codemirror/theme/mbo.css",
      "mdn-like": "/static/components/codemirror/theme/mdn-like.css",
      "midnight": "/static/components/codemirror/theme/midnight.css",
      "monokai": "/static/components/codemirror/theme/monokai.css",
      "neat": "/static/components/codemirror/theme/neat.css",
      "neo": "/static/components/codemirror/theme/neo.css",
      "night": "/static/components/codemirror/theme/night.css",
      "paraiso-dark": "/static/components/codemirror/theme/paraiso-dark.css",
      "paraiso-light": "/static/components/codemirror/theme/paraiso-light.css",
      "pastel-on-dark": "/static/components/codemirror/theme/pastel-on-dark.css",
      "rubyblue": "/static/components/codemirror/theme/rubyblue.css",
      "seti": "/static/components/codemirror/theme/seti.css",
      "solarized": "/static/components/codemirror/theme/solarized.css",
      "the-matrix": "/static/components/codemirror/theme/the-matrix.css",
      "tomorrow-night-bright": "/static/components/codemirror/theme/tomorrow-night-bright.css",
      "tomorrow-night-eighties": "/static/components/codemirror/theme/tomorrow-night-eighties.css",
      "ttcn": "/static/components/codemirror/theme/ttcn.css",
      "twilight": "/static/components/codemirror/theme/twilight.css",
      "vibrant-ink": "/static/components/codemirror/theme/vibrant-ink.css",
      "xq-dark": "/static/components/codemirror/theme/xq-dark.css",
      "xq-light": "/static/components/codemirror/theme/xq-light.css",
      "yeti": "/static/components/codemirror/theme/yeti.css",
      "zenburn": "/static/components/codemirror/theme/zenburn.css"
    };

    var fonts = {
      "Default": {
        "css": "monospace",
        "url": null
      },
      "Hack": {
        "css": "Hack",
        "url": "//cdn.jsdelivr.net/font-hack/2.019/css/hack-extended.min.css"
      },
      "Inconsolata": {
        "css": "Inconsolata",
        "url": "//fonts.googleapis.com/css?family=Inconsolata"
      },
      "Source Code Pro": {
        "css": "Source Code Pro",
        "url": "//fonts.googleapis.com/css?family=Source+Code+Pro"
      },
      "Roboto Mono": {
        "css": "Roboto Mono",
        "url": "//fonts.googleapis.com/css?family=Roboto+Mono"
      },
      "Droid Sans Mono": {
        "css": "Droid Sans Mono",
        "url": "//fonts.googleapis.com/css?family=Droid+Sans+Mono"
      },
      "Ubuntu Mono": {
        "css": "Ubuntu Mono",
        "url": "//fonts.googleapis.com/css?family=Ubuntu+Mono"
      },
      "PT Mono": {
        "css": "PT Mono",
        "url": "//fonts.googleapis.com/css?family=PT+Mono"
      },
      "Fira Mono":{
        "css": "Fira Mono",
        "url": "//fonts.googleapis.com/css?family=Fira+Mono"
      }
    };

    var CELLS, CODE_CELL;

    function add_to_toolbar(current_theme) {

        var cell_menu = $('#cell_menu'),
          divider = $('<li/>').addClass('divider'),
          theme_btn = $('<li/>').addClass('dropdown-submenu'),
          theme_txt = $('<a/>').text('Code Syntax Theme').attr('href', '#'),
          theme_list = $('<ul/>').addClass('dropdown-menu').attr('id', 'theme_select'),
          font_btn = $('<li/>').addClass('dropdown-submenu'),
          font_txt = $('<a/>').text('Code Font').attr('href', '#'),
          font_list = $('<ul/>').addClass('dropdown-menu').attr('id', 'font_select'),
          line_btn = $('<li/>'),
          line_txt = $('<a/>').text('Code Line Numbers').attr('href', '#');

        // Add label to the toolbar
        cell_menu
          .append(divider)
          .append(theme_btn.append(theme_txt).append(theme_list))
          .append(font_btn.append(font_txt).append(font_list))
          .append(line_btn.append(line_txt));

        // Add themes to the selector
        for (var key in themes){
            theme_list.append(
              $('<li/>').append(
                $('<a/>').text(key)
                  .attr('href', '#')
                  .attr('data-value', key)
              )
            );
        }

        theme_list.click(
          function(e){
            e.preventDefault;
            if (e.target.tagName === "A"){
                theme_toggle($(e.target).data("value"));
            }
          }
        );

        // Add fonts to the selector
        for (var key in fonts){
            font_list.append(
              $('<li/>').append(
                $('<a/>').text(key)
                  .attr('href', '#')
                  .attr('data-key', key)
                  .attr('data-css', fonts[key].css)
                  .attr('data-url', fonts[key].url)
              )
            );
        }

        font_list.click(
          function(e){
            e.preventDefault;
            if (e.target.tagName === "A"){
                font_toggle(
                  $(e.target).data("key"),
                  $(e.target).data("css"),
                  $(e.target).data("url")
                );
            }
          }
        );

        // Toggle line numbers
        line_txt.click(
          function(e){
            e.preventDefault;

            var opt = CODE_CELL.config.data.CodeCell.cm_config.lineNumbers;
            var config = CODE_CELL.config;
            var patch = {
              CodeCell:{
                cm_config:{
                  lineNumbers: !opt
                }
              }
            }
            config.update(patch);

            for (var i = 0; i < CELLS.length; i++){
              if(CELLS[i].cell_type == "code"){
                CELLS[i].code_mirror.setOption('lineNumbers', !opt);
              }
            }

          }
        );

    }

    function load_css(theme) {
        // Create a link element to attach the styles
        var link = document.createElement("link");
        link.type = "text/css";
        link.rel = "stylesheet";
        link.href = require.toUrl(themes[theme]);
        link.id = theme + "-css";
        document.getElementsByTagName("head")[0].appendChild(link);
    }

    function load_font(href) {
      // Create a link element to attach the font
      var link = document.createElement("link");
      link.type = "text/css";
      link.rel = "stylesheet";
      link.href = href;
      document.getElementsByTagName("head")[0].appendChild(link);
    }

    function css_toggle(font) {

      var style = document.getElementById("font-css");

      if (!style){
        // Create a style element
        var style = document.createElement("style");
        style.type = "text/css";
        style.id = "font-css"
        document.head.appendChild(style);
      }

      style.innerText = ".CodeMirror {font-family: z;}".replace("z", font);

    }

    function theme_toggle(new_theme) {

      new_theme = (new_theme === "Default")? "ipython" : new_theme;

      if(new_theme !== "ipython") load_css(new_theme);

      var config = CODE_CELL.config;
      var patch = {
        CodeCell:{
          cm_config:{
            theme: new_theme
          }
        }
      }
      config.update(patch);

      for (var i = 0; i < CELLS.length; i++){
        if(CELLS[i].cell_type == "code"){
          CELLS[i].code_mirror.setOption('theme', new_theme);
        }
      }

    }

    function font_toggle(key, css, url) {

      var config = CODE_CELL.config;
      var patch = {
        CodeCell:{
          cm_config:{
            font_family: key
          }
        }
      }
      config.update(patch);

      if (key !== "default") {
        load_font(url);
      }

      css_toggle(css);

    }

    function load_cells() {

        for (var i = 0; i < CELLS.length; i++){
          if(CELLS[i].cell_type == "code"){
            CODE_CELL = CELLS[i];
            break;
          }
        }

        try {
          var theme = CODE_CELL.config.data.CodeCell.cm_config.theme;
          var key = CODE_CELL.config.data.CodeCell.cm_config.font_family;

          load_css(theme);

          if (key !== "default") {
            load_font(fonts[key].url);
            css_toggle(fonts[key].css);
          }
        }
        catch(error) {
          console.log(error);
        }

        add_to_toolbar();
    }

    function load_ipython_extension() {

        CELLS = Jupyter.notebook.get_cells();

        if (CELLS.length < 1) {
            setTimeout(function(){
                load_ipython_extension();
            },250);
        }
        else {
            load_cells()
        }

    }

    return { load_ipython_extension: load_ipython_extension };

});
<|endoftext|>