<commit_before>/*! angular-deckgrid (v0.5.0) - Copyright: 2013 - 2014, André König (andre.koenig@posteo.de) - MIT */
/*
 * angular-deckgrid
 *
 * Copyright(c) 2013-2014 André König <andre.koenig@posteo.de>
 * MIT Licensed
 *
 */

/**
 * @author André König (andre.koenig@posteo.de)
 *
 */

angular.module('akoenig.deckgrid', []);

angular.module('akoenig.deckgrid').directive('deckgrid', [

    'DeckgridDescriptor',

    function initialize (DeckgridDescriptor) {

        'use strict';

        return DeckgridDescriptor.create();
    }
]);
/*
 * angular-deckgrid
 *
 * Copyright(c) 2013-2014 André König <andre.koenig@posteo.de>
 * MIT Licensed
 *
 */

/**
 * @author André König (andre.koenig@posteo.de)
 *
 */

angular.module('akoenig.deckgrid').factory('DeckgridDescriptor', [

    'Deckgrid',
    '$templateCache',
    '$window',
    '$q',
    '$timeout',

    function initialize (Deckgrid, $templateCache, $window, $q, $timeout) {

        'use strict';

        /**
         * This is a wrapper around the AngularJS
         * directive description object.
         *
         */
        function Descriptor () {
            this.restrict = 'AE';

            this.template = '
' +
                                '

' +
                            '
';

            this.scope = {
                'model': '=source'
            };

            //
            // Will be created in the linking function.
            //
            this.$$deckgrid = null;

            this.transclude = true;
            this.link = this.$$link.bind(this);

            //
            // Will be incremented if using inline templates.
            //
            this.$$templateKeyIndex = 0;

        }

        /**
         * @private
         *
         * Cleanup method. Will be called when the
         * deckgrid directive should be destroyed.
         *
         */
        Descriptor.prototype.$$destroy = function $$destroy () {
            this.$$deckgrid.destroy();
        };

        /**
         * @private
         *
         * The deckgrid link method. Will instantiate the deckgrid.
         *
         */
        Descriptor.prototype.$$link = function $$link (scope, elem, attrs, nullController, transclude) {
            var templateKey = 'deckgrid/innerHtmlTemplate' + (++this.$$templateKeyIndex) + '.html',
                self = this,
                styleReady = $q.defer(),
                domWatch;

            scope.$on('$destroy', this.$$destroy.bind(this));

            if (attrs.cardtemplate === undefined) {
                if (attrs.cardtemplatestring === undefined) {
                    // use the provided inner html as template
                    transclude(scope, function onTransclude (innerHTML) {
                        var extractedInnerHTML = [],
                            i = 0,
                            len = innerHTML.length,
                            outerHTML;

                        for (i; i < len; i = i + 1) {
                            outerHTML = innerHTML[i].outerHTML;

                            if (outerHTML !== undefined) {
                                extractedInnerHTML.push(outerHTML);
                            }
                        }

                        $templateCache.put(templateKey, extractedInnerHTML.join());
                    });
                } else {
                    // use the provided template string
                    //
                    // note: the attr is accessed via the elem object, as the attrs content
                    // is already compiled and thus lacks the {{...}} expressions
                    $templateCache.put(templateKey, elem.attr('cardtemplatestring'));
                }

                scope.cardTemplate = templateKey;
            } else {
                // use the provided template file
                scope.cardTemplate = attrs.cardtemplate;
            }

            scope.mother = scope.$parent;

            // Wait for style to be ready on deckgrid element
           domWatch = scope.$watch(function() {
                return $window.getComputedStyle(elem[0], ':before').content;
            }, function(content) {
                if (content !== '') {
                    styleReady.resolve();
                    // Clear the watcher once element is initialized
                    domWatch();
                }
            });
            styleReady.promise.then(function() {
                // Fixes an issue in IE where the width of the elem is accessed before the page is loaded.
                // So, it would be 'auto' instead of resolved pixel value.
                $timeout(function() {
                    self.$$deckgrid = Deckgrid.create(scope, elem[0]);
                });
            });
        };

        return {
            create : function create () {
                return new Descriptor();
            }
        };
    }
]);

/*
 * angular-deckgrid
 *
 * Copyright(c) 2013-2014 André König <andre.koenig@posteo.de>
 * MIT Licensed
 *
 */

/**
 * @author André König (andre.koenig@posteo.de)
 *
 */

angular.module('akoenig.deckgrid').factory('Deckgrid', [

    '$window',
    '$log',

    function initialize ($window, $log) {

        'use strict';

        /**
         * The deckgrid directive.
         *
         */
        function Deckgrid (scope, element) {
            var self = this,
                watcher,
                mql;

            this.$$elem = element;
            this.$$watchers = [];

            this.$$scope = scope;
            this.$$scope.columns = [];

            //
            // The layout configuration will be parsed from
            // the pseudo "before element." There you have to save all
            // the column configurations.
            //
            this.$$scope.layout = this.$$getLayout();

            this.$$createColumns();

            //
            // Register model change.
            //
            watcher = this.$$scope.$watchCollection('model', this.$$onModelChange.bind(this));

            this.$$watchers.push(watcher);

            //
            // Register media query change events.
            //
            angular.forEach(self.$$getMediaQueries(), function onIteration (rule) {
                var handler = self.$$onMediaQueryChange.bind(self);

                function onDestroy () {
                    rule.removeListener(handler);
                }

                rule.addListener(handler);

                self.$$watchers.push(onDestroy);
            });

            mql = $window.matchMedia('(orientation: portrait)');
            mql.addListener(self.$$onMediaQueryChange.bind(self));

        }

        /**
         * @private
         *
         * Extracts the media queries out of the stylesheets.
         *
         * This method will fetch the media queries out of the stylesheets that are
         * responsible for styling the angular-deckgrid.
         *
         * @return {array} An array with all respective styles.
         *
         */
        Deckgrid.prototype.$$getMediaQueries = function $$getMediaQueries () {
            var stylesheets = [],
                mediaQueries = [];

            stylesheets = Array.prototype.concat.call(
                Array.prototype.slice.call(document.querySelectorAll('style[type=\'text/css\']')),
                Array.prototype.slice.call(document.querySelectorAll('link[rel=\'stylesheet\']'))
            );

            function extractRules (stylesheet) {
                try {
                    return (stylesheet.sheet.cssRules || []);
                } catch (e) {
                    return [];
                }
            }

            function hasDeckgridStyles (rule) {
                var regexe   = /\[(\w*-)?deckgrid\]::?before/g,
                    i        = 0,
                    selector = '';

                if (!rule.media || angular.isUndefined(rule.cssRules)) {
                    return false;
                }

                i = rule.cssRules.length - 1;

                for (i; i >= 0; i = i - 1) {
                    selector = rule.cssRules[i].selectorText;

                    if (angular.isDefined(selector) && selector.match(regexe)) {
                        return true;
                    }
                }

                return false;
            }

            angular.forEach(stylesheets, function onIteration (stylesheet) {
                var rules = extractRules(stylesheet);

                angular.forEach(rules, function inRuleIteration (rule) {
                    if (hasDeckgridStyles(rule)) {
                        mediaQueries.push($window.matchMedia(rule.media.mediaText));
                    }
                });
            });

            return mediaQueries;
        };

        /**
         * @private
         *
         * Creates the column segmentation. With other words:
         * This method creates the internal data structure from the
         * passed "source" attribute. Every card within this "source"
         * model will be passed into this internal column structure by
         * reference. So if you modify the data within your controller
         * this directive will reflect these changes immediately.
         *
         * NOTE that calling this method will trigger a complete template "redraw".
         *
         */
        Deckgrid.prototype.$$createColumns = function $$createColumns () {
            var self = this;

            if (!this.$$scope.layout) {
                return $log.error('angular-deckgrid: No CSS configuration found (see ' +
                                   'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)');
            }

            this.$$scope.columns = [];

            angular.forEach(this.$$scope.model, function onIteration (card, index) {
                var column = (index % self.$$scope.layout.columns) | 0;

                if (!self.$$scope.columns[column]) {
                    self.$$scope.columns[column] = [];
                }

                card.$index = index;
                self.$$scope.columns[column].push(card);
            });
        };

        /**
         * @private
         *
         * Parses the configuration out of the configured CSS styles.
         *
         * Example:
         *
         *     .deckgrid::before {
         *         content: '3 .column.size-1-3';
         *     }
         *
         * Will result in a three column grid where each column will have the
         * classes: "column size-1-3".
         *
         * You are responsible for defining the respective styles within your CSS.
         *
         */
        Deckgrid.prototype.$$getLayout = function $$getLayout () {
            var content = $window.getComputedStyle(this.$$elem, ':before').content,
                layout;

            if (content) {
                content = content.replace(/'/g, '');  // before e.g. '3 .column.size-1of3'
                content = content.replace(/"/g, '');  // before e.g. "3 .column.size-1of3"
                content = content.split(' ');

                if (2 === content.length) {
                    layout = {};
                    layout.columns = (content[0] | 0);
                    layout.classList = content[1].replace(/\./g, ' ').trim();
                }
            }

            return layout;
        };

        /**
         * @private
         *
         * Event that will be triggered if a CSS media query changed.
         *
         */
        Deckgrid.prototype.$$onMediaQueryChange = function $$onMediaQueryChange () {
            var self = this,
                layout = this.$$getLayout();

            //
            // Okay, the layout has changed.
            // Creating a new column structure is not avoidable.
            //
            if (layout.columns !== this.$$scope.layout.columns) {
                self.$$scope.layout = layout;

                self.$$scope.$apply(function onApply () {
                    self.$$createColumns();
                });
            }
        };

        /**
         * @private
         *
         * Event that will be triggered when the source model has changed.
         *
         */
        Deckgrid.prototype.$$onModelChange = function $$onModelChange (newModel, oldModel) {
            var self = this;

            newModel = newModel || [];
            oldModel = oldModel || [];

            if (!angular.equals(oldModel, newModel)) {
                self.$$createColumns();
            }
        };

        /**
         * Destroys the directive. Takes care of cleaning all
         * watchers and event handlers.
         *
         */
        Deckgrid.prototype.destroy = function destroy () {
            var i = this.$$watchers.length - 1;

            for (i; i >= 0; i = i - 1) {
                this.$$watchers[i]();
            }
        };

        return {
            create : function create (scope, element) {
                return new Deckgrid(scope, element);
            }
        };
    }
]);
<commit_msg>LIA-46156 adds IE9 fix to look for deckgrid styles<commit_after>/*! angular-deckgrid (v0.5.0) - Copyright: 2013 - 2014, André König (andre.koenig@posteo.de) - MIT */
/*
 * angular-deckgrid
 *
 * Copyright(c) 2013-2014 André König <andre.koenig@posteo.de>
 * MIT Licensed
 *
 */

/**
 * @author André König (andre.koenig@posteo.de)
 *
 */

angular.module('akoenig.deckgrid', []);

angular.module('akoenig.deckgrid').directive('deckgrid', [

    'DeckgridDescriptor',

    function initialize (DeckgridDescriptor) {

        'use strict';

        return DeckgridDescriptor.create();
    }
]);
/*
 * angular-deckgrid
 *
 * Copyright(c) 2013-2014 André König <andre.koenig@posteo.de>
 * MIT Licensed
 *
 */

/**
 * @author André König (andre.koenig@posteo.de)
 *
 */

angular.module('akoenig.deckgrid').factory('DeckgridDescriptor', [

    'Deckgrid',
    '$templateCache',
    '$window',
    '$q',
    '$timeout',

    function initialize (Deckgrid, $templateCache, $window, $q, $timeout) {

        'use strict';

        /**
         * This is a wrapper around the AngularJS
         * directive description object.
         *
         */
        function Descriptor () {
            this.restrict = 'AE';

            this.template = '
' +
                                '

' +
                            '
';

            this.scope = {
                'model': '=source'
            };

            //
            // Will be created in the linking function.
            //
            this.$$deckgrid = null;

            this.transclude = true;
            this.link = this.$$link.bind(this);

            //
            // Will be incremented if using inline templates.
            //
            this.$$templateKeyIndex = 0;

        }

        /**
         * @private
         *
         * Cleanup method. Will be called when the
         * deckgrid directive should be destroyed.
         *
         */
        Descriptor.prototype.$$destroy = function $$destroy () {
            this.$$deckgrid.destroy();
        };

        /**
         * @private
         *
         * The deckgrid link method. Will instantiate the deckgrid.
         *
         */
        Descriptor.prototype.$$link = function $$link (scope, elem, attrs, nullController, transclude) {
            var templateKey = 'deckgrid/innerHtmlTemplate' + (++this.$$templateKeyIndex) + '.html',
                self = this,
                styleReady = $q.defer(),
                domWatch;

            scope.$on('$destroy', this.$$destroy.bind(this));

            if (attrs.cardtemplate === undefined) {
                if (attrs.cardtemplatestring === undefined) {
                    // use the provided inner html as template
                    transclude(scope, function onTransclude (innerHTML) {
                        var extractedInnerHTML = [],
                            i = 0,
                            len = innerHTML.length,
                            outerHTML;

                        for (i; i < len; i = i + 1) {
                            outerHTML = innerHTML[i].outerHTML;

                            if (outerHTML !== undefined) {
                                extractedInnerHTML.push(outerHTML);
                            }
                        }

                        $templateCache.put(templateKey, extractedInnerHTML.join());
                    });
                } else {
                    // use the provided template string
                    //
                    // note: the attr is accessed via the elem object, as the attrs content
                    // is already compiled and thus lacks the {{...}} expressions
                    $templateCache.put(templateKey, elem.attr('cardtemplatestring'));
                }

                scope.cardTemplate = templateKey;
            } else {
                // use the provided template file
                scope.cardTemplate = attrs.cardtemplate;
            }

            scope.mother = scope.$parent;

            // Wait for style to be ready on deckgrid element
           domWatch = scope.$watch(function() {
                return $window.getComputedStyle(elem[0], ':before').content;
            }, function(content) {
                if (content !== '') {
                    styleReady.resolve();
                    // Clear the watcher once element is initialized
                    domWatch();
                }
            });
            styleReady.promise.then(function() {
                // Fixes an issue in IE where the width of the elem is accessed before the page is loaded.
                // So, it would be 'auto' instead of resolved pixel value.
                $timeout(function() {
                    self.$$deckgrid = Deckgrid.create(scope, elem[0]);
                });
            });
        };

        return {
            create : function create () {
                return new Descriptor();
            }
        };
    }
]);

/*
 * angular-deckgrid
 *
 * Copyright(c) 2013-2014 André König <andre.koenig@posteo.de>
 * MIT Licensed
 *
 */

/**
 * @author André König (andre.koenig@posteo.de)
 *
 */

angular.module('akoenig.deckgrid').factory('Deckgrid', [

    '$window',
    '$log',

    function initialize ($window, $log) {

        'use strict';

        /**
         * The deckgrid directive.
         *
         */
        function Deckgrid (scope, element) {
            var self = this,
                watcher,
                mql;

            this.$$elem = element;
            this.$$watchers = [];

            this.$$scope = scope;
            this.$$scope.columns = [];

            //
            // The layout configuration will be parsed from
            // the pseudo "before element." There you have to save all
            // the column configurations.
            //
            this.$$scope.layout = this.$$getLayout();

            this.$$createColumns();

            //
            // Register model change.
            //
            watcher = this.$$scope.$watchCollection('model', this.$$onModelChange.bind(this));

            this.$$watchers.push(watcher);

            //
            // Register media query change events.
            //
            angular.forEach(self.$$getMediaQueries(), function onIteration (rule) {
                var handler = self.$$onMediaQueryChange.bind(self);

                function onDestroy () {
                    rule.removeListener(handler);
                }

                rule.addListener(handler);

                self.$$watchers.push(onDestroy);
            });

            mql = $window.matchMedia('(orientation: portrait)');
            mql.addListener(self.$$onMediaQueryChange.bind(self));

        }

        /**
         * @private
         *
         * Extracts the media queries out of the stylesheets.
         *
         * This method will fetch the media queries out of the stylesheets that are
         * responsible for styling the angular-deckgrid.
         *
         * @return {array} An array with all respective styles.
         *
         */
        Deckgrid.prototype.$$getMediaQueries = function $$getMediaQueries () {
            var stylesheets = [],
                mediaQueries = [];

            stylesheets = Array.prototype.concat.call(
                Array.prototype.slice.call(document.querySelectorAll('style[type=\'text/css\']')),
                Array.prototype.slice.call(document.querySelectorAll('link[rel=\'stylesheet\']'))
            );

            function extractRules (stylesheet) {
                try {
                    return (stylesheet.sheet.cssRules || []);
                } catch (e) {
                    return [];
                }
            }

            function hasDeckgridStyles (rule) {
                // IE 9 treats .lia-deckgrid[deckgrid]::before as [deckgrid].lia-deckgrid::before
                // short notation of  \[(\w*-)?deckgrid\]::?before|\[(\w*-)?deckgrid\][\.#][\w-]*::?before
                var regexe   = /(\[(\w*-)?deckgrid\]|\[(\w*-)?deckgrid\][\.#][\w-]*)::?before/g,
                    i        = 0,
                    selector = '';

                if (!rule.media || angular.isUndefined(rule.cssRules)) {
                    return false;
                }

                i = rule.cssRules.length - 1;

                for (i; i >= 0; i = i - 1) {
                    selector = rule.cssRules[i].selectorText;

                    if (angular.isDefined(selector) && selector.match(regexe)) {
                        return true;
                    }
                }

                return false;
            }

            angular.forEach(stylesheets, function onIteration (stylesheet) {
                var rules = extractRules(stylesheet);

                angular.forEach(rules, function inRuleIteration (rule) {
                    if (hasDeckgridStyles(rule)) {
                        mediaQueries.push($window.matchMedia(rule.media.mediaText));
                    }
                });
            });

            return mediaQueries;
        };

        /**
         * @private
         *
         * Creates the column segmentation. With other words:
         * This method creates the internal data structure from the
         * passed "source" attribute. Every card within this "source"
         * model will be passed into this internal column structure by
         * reference. So if you modify the data within your controller
         * this directive will reflect these changes immediately.
         *
         * NOTE that calling this method will trigger a complete template "redraw".
         *
         */
        Deckgrid.prototype.$$createColumns = function $$createColumns () {
            var self = this;

            if (!this.$$scope.layout) {
                return $log.error('angular-deckgrid: No CSS configuration found (see ' +
                                   'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)');
            }

            this.$$scope.columns = [];

            angular.forEach(this.$$scope.model, function onIteration (card, index) {
                var column = (index % self.$$scope.layout.columns) | 0;

                if (!self.$$scope.columns[column]) {
                    self.$$scope.columns[column] = [];
                }

                card.$index = index;
                self.$$scope.columns[column].push(card);
            });
        };

        /**
         * @private
         *
         * Parses the configuration out of the configured CSS styles.
         *
         * Example:
         *
         *     .deckgrid::before {
         *         content: '3 .column.size-1-3';
         *     }
         *
         * Will result in a three column grid where each column will have the
         * classes: "column size-1-3".
         *
         * You are responsible for defining the respective styles within your CSS.
         *
         */
        Deckgrid.prototype.$$getLayout = function $$getLayout () {
            var content = $window.getComputedStyle(this.$$elem, ':before').content,
                layout;

            if (content) {
                content = content.replace(/'/g, '');  // before e.g. '3 .column.size-1of3'
                content = content.replace(/"/g, '');  // before e.g. "3 .column.size-1of3"
                content = content.split(' ');

                if (2 === content.length) {
                    layout = {};
                    layout.columns = (content[0] | 0);
                    layout.classList = content[1].replace(/\./g, ' ').trim();
                }
            }

            return layout;
        };

        /**
         * @private
         *
         * Event that will be triggered if a CSS media query changed.
         *
         */
        Deckgrid.prototype.$$onMediaQueryChange = function $$onMediaQueryChange () {
            var self = this,
                layout = this.$$getLayout();

            //
            // Okay, the layout has changed.
            // Creating a new column structure is not avoidable.
            //
            if (layout.columns !== this.$$scope.layout.columns) {
                self.$$scope.layout = layout;

                self.$$scope.$apply(function onApply () {
                    self.$$createColumns();
                });
            }
        };

        /**
         * @private
         *
         * Event that will be triggered when the source model has changed.
         *
         */
        Deckgrid.prototype.$$onModelChange = function $$onModelChange (newModel, oldModel) {
            var self = this;

            newModel = newModel || [];
            oldModel = oldModel || [];

            if (!angular.equals(oldModel, newModel)) {
                self.$$createColumns();
            }
        };

        /**
         * Destroys the directive. Takes care of cleaning all
         * watchers and event handlers.
         *
         */
        Deckgrid.prototype.destroy = function destroy () {
            var i = this.$$watchers.length - 1;

            for (i; i >= 0; i = i - 1) {
                this.$$watchers[i]();
            }
        };

        return {
            create : function create (scope, element) {
                return new Deckgrid(scope, element);
            }
        };
    }
]);
<|endoftext|>


<commit_before>var service = null;
var privateGadgetNames = null;
var nameOfGadgetBeingEdited = '';
var entryOfGadgetBeingEdited = null;
var privateGadgetSpecFeedUrl = null;

var SERVICE_NAME = 'esp';
var APP_NAME = 'private-gadget-editor';

var SPINNER = '';
var DEFAULT_SPINNER_ID = 'spinner';

function $(id) {
  return document.getElementById(id);
};

function startSpinner(id) {
  $(id ? id : DEFAULT_SPINNER_ID).innerHTML = SPINNER;
};

function stopSpinner(id) {
  $(id ? id : DEFAULT_SPINNER_ID).innerHTML = '';
};

function initEditor() {
  if (privateGadgetSpecFeedUrl) {
    initGadgetNameList();
  }
};

function noCache(url) {
  return url + '?nocache=' + (new Date().getTime());
};

function setNameOfGadgetBeingEdited(name) {
  nameOfGadgetBeingEdited = name;
  if (name) {
    $('spec-url-wrapper').style.display = 'inline';
    var specUrl = 'http://www.google.com/a/feeds/server/g/domain/' +
       detectDomainName() + '/PrivateGadgetSpec/' + name;
    $('spec-url').href = specUrl;
  } else {
    $('spec-url-wrapper').style.display = 'none';
  }
};

function initGadgetNameList() {
  service = new google.gdata.client.FeedServerService(SERVICE_NAME, APP_NAME);
  service.setGadgetsAuthentication('SIGNED');
  service.getFeed(noCache(privateGadgetSpecFeedUrl), function(response) {
    stopSpinner();
    var entries = response && response.feed.entry ? response.feed.entry : [];
    showPrivateGadgetNames(setPrivateGadgetNames(entries));
  }, function(response) {
    stopSpinner()
    showMessage('Error: failed to load private gadget specs');
  });
  startSpinner();
};

function setPrivateGadgetNames(entries) {
  privateGadgetNames = [];
  for (var i = 0; i < entries.length; i++) {
    var name = entries[i].id.$t;
    name = name.substring(name.lastIndexOf('/') + 1);
    privateGadgetNames.push(name);
  }
  return privateGadgetNames;
};

function showPrivateGadgetNames() {
  var html = ['<select id="gadget-select" onchange="editSelectedGadget()">'];
  html.push('<option value="">Select to open</option>');
  for (var i = 0; i < privateGadgetNames.length; i++) {
    var privateGadgetName = privateGadgetNames[i];
    html.push('<option ', privateGadgetName == nameOfGadgetBeingEdited ? 'selected' : '',
        '>', privateGadgetName, '</option>');
  }
  document.getElementById('gadget-list').innerHTML = html.join('');
};

function getSelectedGadgetName() {
  return document.getElementById('gadget-select').value;
};

function editSelectedGadget() {
  var name = getSelectedGadgetName();
  if (name) {
    service.getEntry(noCache(privateGadgetSpecFeedUrl + '/' + name), function(response) {
      stopSpinner();
      setNameOfGadgetBeingEdited(name);
      entryOfGadgetBeingEdited = response.entry;
      editor.setCode(response.entry.content.entity.specContent);
      editor.editor.syntaxHighlight('init');
    }, function(response) {
      stopSpinner();
      showMessage('Error: failed to open gadget spec "' + name + '"');
    });
    startSpinner();
  } else {
    newGadget();
  }
};

function deleteSelectedGadget() {
  var name = getSelectedGadgetName();
  if (name) {
    service.deleteEntry(privateGadgetSpecFeedUrl + '/' + name, function(response) {
      stopSpinner();
      initEditor();
      newGadget();
    }, function(response) {
      stopSpinner();
      showMessage('Error: failed to delete gadget spec "' + name + '"');
    });
    startSpinner();
  } else {
    alert('Please select a gadget to delete.');
  }
};

function newGadget() {
  setNameOfGadgetBeingEdited('');
  editor.setCode(getGadgetSpecTemplate());
  editor.editor.syntaxHighlight('init');
  showPrivateGadgetNames();
  entryOfGadgetBeingEdited = {xmlns: 'http://www.w3.org/2005/Atom', content: {
      type: 'application/xml', entity: {name: '', specContent: ''}}};
};

function saveGadget(changeName) {
  entryOfGadgetBeingEdited.content.entity.specContent = editor.getCode();
  if (nameOfGadgetBeingEdited && !changeName) {
    service.updateEntry(privateGadgetSpecFeedUrl + '/' + nameOfGadgetBeingEdited,
        entryOfGadgetBeingEdited, function(response) {
      stopSpinner();
    }, function(response) {
      stopSpinner();
      showMessage('Error: failed to update gadget spec "' + nameOfGadgetBeingEdited + '"');
    });
    startSpinner();
  } else {
    var name = changeName ?
      prompt('Please enter new name of gadget (e.g. hello.xml)') :
      prompt('Please enter name of new gadget (e.g. hello.xml)');
    if (!name) {
      return;
    }
    setNameOfGadgetBeingEdited(name);
    if (nameOfGadgetBeingEdited) {
      entryOfGadgetBeingEdited.content.entity.name = nameOfGadgetBeingEdited;
      service.insertEntry(privateGadgetSpecFeedUrl,
          entryOfGadgetBeingEdited, function(response) {
        stopSpinner();
        privateGadgetNames.push(nameOfGadgetBeingEdited);
        showPrivateGadgetNames();
      }, function(response) {
        stopSpinner();
        showMessage('Error: failed to add gadget spec "' + nameOfGadgetBeingEdited + '"');
      });
      startSpinner();
    }
  }
};

function openGadgetByUrl() {
  var gadgetSpecUrl = prompt('Please enter public URL of gadget spec');
  if (gadgetSpecUrl) {
    var params = {};
    params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;
    gadgets.io.makeRequest(gadgetSpecUrl, function(response) {
      if (response.rc > 299) {
        showMessage('Error: ' + response.errors);
      } else {
        setNameOfGadgetBeingEdited(null);
        entryOfGadgetBeingEdited = {xmlns: 'http://www.w3.org/2005/Atom', content: {
          type: 'application/xml', entity: {name: '', specContent: response.text}}};
        editor.setCode(response.text);
        editor.editor.syntaxHighlight('init');
      }
    }, params);
  }
};

function getGadgetSpecTemplate() {
  var textArea = document.getElementById('gadget-spec-template');
  return textArea.value || textArea.defaultValue;
};

function showMessage(message) {
  var miniMessage = new gadgets.MiniMessage(null, document.getElementById('message-box'));
  miniMessage.createDismissibleMessage(message);
};

//// google.load('gdata', '1.x', {packages: ['core']});
// google.load('gdata', '1.x', {packages: ['core'], 'other_params': 'debug=1'});
// google.setOnLoadCallback(initEditor);

function initCodePress() {
  editor.style.height = '400px';
  CodePressWrapper.init();
};

function detectDomainName() {
  var params = location.href.split('&');
  for (var i = 0; i < params.length; i++) {
    if (params[i].indexOf('parent=') == 0) {
      var p = params[i].split('=');
      var parent = decodeURIComponent(p[1]);
      var r = /google.com\/a\/([^\/]*)\//.exec(parent);
      var domainName = r ? r[1] : null;
      return domainName;
    }
  }

  return null;
};

function initGadget() {
  var domainName = detectDomainName();
  if (domainName) {
    privateGadgetSpecFeedUrl = 'http://feedserver-enterprise.googleusercontent.com/a/' +
        domainName + '/g/PrivateGadgetSpec';
  } else {
    showMessage('Error: domain name missing');
  }

  gadgets.window.adjustHeight();
};

function init() {
  initCodePress();
  initGadget();
  initEditor();
};

gadgets.util.registerOnLoadHandler(init);
<commit_msg>changed spinner URL to proxied version to avoid mixed content and auth<commit_after>var service = null;
var privateGadgetNames = null;
var nameOfGadgetBeingEdited = '';
var entryOfGadgetBeingEdited = null;
var privateGadgetSpecFeedUrl = null;

var SERVICE_NAME = 'esp';
var APP_NAME = 'private-gadget-editor';

var SPINNER = '';
var DEFAULT_SPINNER_ID = 'spinner';

function $(id) {
  return document.getElementById(id);
};

function startSpinner(id) {
  $(id ? id : DEFAULT_SPINNER_ID).innerHTML = SPINNER;
};

function stopSpinner(id) {
  $(id ? id : DEFAULT_SPINNER_ID).innerHTML = '';
};

function initEditor() {
  if (privateGadgetSpecFeedUrl) {
    initGadgetNameList();
  }
};

function noCache(url) {
  return url + '?nocache=' + (new Date().getTime());
};

function setNameOfGadgetBeingEdited(name) {
  nameOfGadgetBeingEdited = name;
  if (name) {
    $('spec-url-wrapper').style.display = 'inline';
    var specUrl = 'http://www.google.com/a/feeds/server/g/domain/' +
        detectDomainName() + '/PrivateGadgetSpec/' + name;
    $('spec-url').href = specUrl;
  } else {
    $('spec-url-wrapper').style.display = 'none';
  }
};

function initGadgetNameList() {
  service = new google.gdata.client.FeedServerService(SERVICE_NAME, APP_NAME);
  service.setGadgetsAuthentication('SIGNED');
  service.getFeed(noCache(privateGadgetSpecFeedUrl), function(response) {
    stopSpinner();
    var entries = response && response.feed.entry ? response.feed.entry : [];
    showPrivateGadgetNames(setPrivateGadgetNames(entries));
  }, function(response) {
    stopSpinner()
    showMessage('Error: failed to load private gadget specs');
  });
  startSpinner();
};

function setPrivateGadgetNames(entries) {
  privateGadgetNames = [];
  for (var i = 0; i < entries.length; i++) {
    var name = entries[i].id.$t;
    name = name.substring(name.lastIndexOf('/') + 1);
    privateGadgetNames.push(name);
  }
  return privateGadgetNames;
};

function showPrivateGadgetNames() {
  var html = ['<select id="gadget-select" onchange="editSelectedGadget()">'];
  html.push('<option value="">Select to open</option>');
  for (var i = 0; i < privateGadgetNames.length; i++) {
    var privateGadgetName = privateGadgetNames[i];
    html.push('<option ', privateGadgetName == nameOfGadgetBeingEdited ? 'selected' : '',
        '>', privateGadgetName, '</option>');
  }
  document.getElementById('gadget-list').innerHTML = html.join('');
};

function getSelectedGadgetName() {
  return document.getElementById('gadget-select').value;
};

function editSelectedGadget() {
  var name = getSelectedGadgetName();
  if (name) {
    service.getEntry(noCache(privateGadgetSpecFeedUrl + '/' + name), function(response) {
      stopSpinner();
      setNameOfGadgetBeingEdited(name);
      entryOfGadgetBeingEdited = response.entry;
      editor.setCode(response.entry.content.entity.specContent);
      editor.editor.syntaxHighlight('init');
    }, function(response) {
      stopSpinner();
      showMessage('Error: failed to open gadget spec "' + name + '"');
    });
    startSpinner();
  } else {
    newGadget();
  }
};

function deleteSelectedGadget() {
  var name = getSelectedGadgetName();
  if (name) {
    service.deleteEntry(privateGadgetSpecFeedUrl + '/' + name, function(response) {
      stopSpinner();
      initEditor();
      newGadget();
    }, function(response) {
      stopSpinner();
      showMessage('Error: failed to delete gadget spec "' + name + '"');
    });
    startSpinner();
  } else {
    alert('Please select a gadget to delete.');
  }
};

function newGadget() {
  setNameOfGadgetBeingEdited('');
  editor.setCode(getGadgetSpecTemplate());
  editor.editor.syntaxHighlight('init');
  showPrivateGadgetNames();
  entryOfGadgetBeingEdited = {xmlns: 'http://www.w3.org/2005/Atom', content: {
      type: 'application/xml', entity: {name: '', specContent: ''}}};
};

function saveGadget(changeName) {
  entryOfGadgetBeingEdited.content.entity.specContent = editor.getCode();
  if (nameOfGadgetBeingEdited && !changeName) {
    service.updateEntry(privateGadgetSpecFeedUrl + '/' + nameOfGadgetBeingEdited,
        entryOfGadgetBeingEdited, function(response) {
      stopSpinner();
    }, function(response) {
      stopSpinner();
      showMessage('Error: failed to update gadget spec "' + nameOfGadgetBeingEdited + '"');
    });
    startSpinner();
  } else {
    var name = changeName ?
      prompt('Please enter new name of gadget (e.g. hello.xml)') :
      prompt('Please enter name of new gadget (e.g. hello.xml)');
    if (!name) {
      return;
    }
    setNameOfGadgetBeingEdited(name);
    if (nameOfGadgetBeingEdited) {
      entryOfGadgetBeingEdited.content.entity.name = nameOfGadgetBeingEdited;
      service.insertEntry(privateGadgetSpecFeedUrl,
          entryOfGadgetBeingEdited, function(response) {
        stopSpinner();
        privateGadgetNames.push(nameOfGadgetBeingEdited);
        showPrivateGadgetNames();
      }, function(response) {
        stopSpinner();
        showMessage('Error: failed to add gadget spec "' + nameOfGadgetBeingEdited + '"');
      });
      startSpinner();
    }
  }
};

function openGadgetByUrl() {
  var gadgetSpecUrl = prompt('Please enter public URL of gadget spec');
  if (gadgetSpecUrl) {
    var params = {};
    params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;
    gadgets.io.makeRequest(gadgetSpecUrl, function(response) {
      if (response.rc > 299) {
        showMessage('Error: ' + response.errors);
      } else {
        setNameOfGadgetBeingEdited(null);
        entryOfGadgetBeingEdited = {xmlns: 'http://www.w3.org/2005/Atom', content: {
          type: 'application/xml', entity: {name: '', specContent: response.text}}};
        editor.setCode(response.text);
        editor.editor.syntaxHighlight('init');
      }
    }, params);
  }
};

function getGadgetSpecTemplate() {
  var textArea = document.getElementById('gadget-spec-template');
  return textArea.value || textArea.defaultValue;
};

function showMessage(message) {
  var miniMessage = new gadgets.MiniMessage(null, document.getElementById('message-box'));
  miniMessage.createDismissibleMessage(message);
};

//// google.load('gdata', '1.x', {packages: ['core']});
// google.load('gdata', '1.x', {packages: ['core'], 'other_params': 'debug=1'});
// google.setOnLoadCallback(initEditor);

function initCodePress() {
  editor.style.height = '400px';
  CodePressWrapper.init();
};

function detectDomainName() {
  var params = location.href.split('&');
  for (var i = 0; i < params.length; i++) {
    if (params[i].indexOf('parent=') == 0) {
      var p = params[i].split('=');
      var parent = decodeURIComponent(p[1]);
      var r = /google.com\/a\/([^\/]*)\//.exec(parent);
      var domainName = r ? r[1] : null;
      return domainName;
    }
  }

  return null;
};

function initGadget() {
  var domainName = detectDomainName();
  if (domainName) {
    privateGadgetSpecFeedUrl = 'http://feedserver-enterprise.googleusercontent.com/a/' +
        domainName + '/g/PrivateGadgetSpec';
  } else {
    showMessage('Error: domain name missing');
  }

  gadgets.window.adjustHeight();
};

function init() {
  initCodePress();
  initGadget();
  initEditor();
};

gadgets.util.registerOnLoadHandler(init);
<|endoftext|>


<commit_before>'use strict';

var React = require('react');

var isTouchDevice = 'ontouchstart' in window || navigator.msMaxTouchPoints > 0;
var draggableEvents = {
    mobile: {
        react: {
            down: 'onTouchStart',
            drag: 'onTouchMove',
            drop: 'onTouchEnd',
            move: 'onTouchMove',
            up: 'onTouchUp'
        },
        native: {
            down: 'touchstart',
            drag: 'touchmove',
            drop: 'touchend',
            move: 'touchmove',
            up: 'touchup'
        }
    },
    desktop: {
        react: {
            down: 'onMouseDown',
            drag: 'onDragOver',
            drop: 'onDrop',
            move: 'onMouseMove',
            up: 'onMouseUp'
        },
        native: {
            down: 'mousedown',
            drag: 'dragStart',
            drop: 'drop',
            move: 'mousemove',
            up: 'mouseup'
        }
    }
};
var deviceEvents = isTouchDevice ? draggableEvents.mobile : draggableEvents.desktop;

var ReactAvatarEditor = React.createClass({
    displayName: 'ReactAvatarEditor',

    propTypes: {
        scale: React.PropTypes.number,
        image: React.PropTypes.string,
        border: React.PropTypes.number,
        width: React.PropTypes.number,
        height: React.PropTypes.number,
        color: React.PropTypes.arrayOf(React.PropTypes.number),
        onImageReady: React.PropTypes.func,
        style: React.PropTypes.object
    },

    getDefaultProps: function getDefaultProps() {
        return {
            scale: 1,
            border: 25,
            width: 200,
            height: 200,
            color: [0, 0, 0, 0.5],
            onImageReady: function onImageReady() {},
            style: {}
        };
    },

    getInitialState: function getInitialState() {
        return {
            drag: false,
            my: null,
            mx: null,
            image: {
                x: 0,
                y: 0
            }
        };
    },

    getDimensions: function getDimensions() {
        return {
            width: this.props.width,
            height: this.props.height,
            border: this.props.border,
            canvas: {
                width: this.props.width + this.props.border * 2,
                height: this.props.height + this.props.border * 2
            }
        };
    },

    getImage: function getImage(type, quality) {
        var dom = document.createElement('canvas');
        var context = dom.getContext('2d');
        var dimensions = this.getDimensions();

        dom.width = dimensions.width;
        dom.height = dimensions.height;

        context.globalCompositeOperation = 'destination-over';

        var imageState = this.state.image;

        this.paintHQImage(dom, context, {
            resource: imageState.resource,
            x: imageState.x - dimensions.border,
            y: imageState.y - dimensions.border,
            width: imageState.width,
            height: imageState.height
        });

        return dom.toDataURL(type, quality);
    },

    isDataURL: function isDataURL(str) {
        var regex = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
        return !!str.match(regex);
    },

    loadImage: function loadImage(imageURL) {
        var imageObj = new Image();
        imageObj.onload = this.handleImageReady.bind(this, imageObj);
        if (!this.isDataURL(imageURL)) imageObj.crossOrigin = 'anonymous';
        imageObj.src = imageURL;
    },

    componentDidMount: function componentDidMount() {
        var context = this.getDOMNode().getContext('2d');
        if (this.props.image) {
            this.loadImage(this.props.image);
        }
        this.paint(context);
        document && document.addEventListener(deviceEvents.native.move, this.handleMouseMove, false);
        document && document.addEventListener(deviceEvents.native.up, this.handleMouseUp, false);

        if (isTouchDevice) React.initializeTouchEvents(true);
    },

    componentWillUnmount: function componentWillUnmount() {
        document && document.removeEventListener(deviceEvents.native.move, this.handleMouseMove, false);
        document && document.removeEventListener(deviceEvents.native.up, this.handleMouseUp, false);
    },

    componentDidUpdate: function componentDidUpdate() {
        var context = this.getDOMNode().getContext('2d');
        context.clearRect(0, 0, this.getDimensions().canvas.width, this.getDimensions().canvas.height);
        this.paint(context);
        this.paintImage(context, this.state.image);
    },

    handleImageReady: function handleImageReady(image) {
        var imageState = this.getInitialSize(image.width, image.height);
        imageState.resource = image;
        imageState.x = this.props.border;
        imageState.y = this.props.border;
        this.setState({ drag: false, image: imageState }, this.props.onImageReady);
    },

    getInitialSize: function getInitialSize(width, height) {
        var newHeight, newWidth, dimensions, canvasRatio, imageRatio;

        dimensions = this.getDimensions();

        canvasRatio = dimensions.height / dimensions.width;
        imageRatio = height / width;

        if (canvasRatio > imageRatio) {
            newHeight = this.getDimensions().height;
            newWidth = width * (newHeight / height);
        } else {
            newWidth = this.getDimensions().width;
            newHeight = height * (newWidth / width);
        }

        return {
            height: newHeight,
            width: newWidth
        };
    },

    componentWillReceiveProps: function componentWillReceiveProps(newProps) {
        if (this.props.image != newProps.image) {
            this.loadImage(newProps.image);
        }
        if (this.props.scale != newProps.scale) {
            this.squeeze(newProps);
        }
    },

    paintImage: function paintImage(context, image) {
        if (image.resource) {
            var position = this.calculatePosition(image);
            context.save();
            context.globalCompositeOperation = 'destination-over';
            context.drawImage(image.resource, image.x, image.y, position.width, position.height);

            context.restore();
        }
    },

    paintHQImage: function paintHQImage(canvas, context, image) {
        if (image.resource) {
            var position = this.calculatePosition(image);
            context.save();
            context.globalCompositeOperation = 'destination-over';

            var scale = image.resource.width / position.width;

            var dimensions = this.getDimensions();
            canvas.width = dimensions.width * scale;
            canvas.height = dimensions.height * scale;

            var x = image.x * scale;
            var y = image.y * scale;

            context.drawImage(image.resource, x, y, image.resource.width, image.resource.height);

            context.restore();
        }
    },

    calculatePosition: function calculatePosition(image) {
        image = image || this.state.image;
        var x,
            y,
            width,
            height,
            dimensions = this.getDimensions();

        width = image.width * this.props.scale;
        height = image.height * this.props.scale;
        var widthDiff = (width - image.width) / 2;
        var heightDiff = (height - image.height) / 2;
        x = image.x - widthDiff;
        y = image.y - heightDiff;

        // top and left border bounding
        x = Math.min(x, dimensions.border);
        y = Math.min(y, dimensions.border);

        // right and bottom
        var fromBottom = height + (y - dimensions.border);
        y = fromBottom > dimensions.height ? y : y + (dimensions.height - fromBottom);
        var fromRight = width + (x - dimensions.border);
        x = fromRight > dimensions.width ? x : x + (dimensions.width - fromRight);

        return {
            x: x,
            y: y,
            height: height,
            width: width
        };
    },

    paint: function paint(context) {
        context.save();
        context.translate(0, 0);
        context.fillStyle = 'rgba(' + this.props.color.slice(0, 4).join(',') + ')';

        var dimensions = this.getDimensions();

        var borderSize = dimensions.border;
        var height = dimensions.canvas.height;
        var width = dimensions.canvas.width;

        context.fillRect(0, 0, width, borderSize); // top
        context.fillRect(0, height - borderSize, width, borderSize); // bottom
        context.fillRect(0, borderSize, borderSize, height - borderSize * 2); // left
        context.fillRect(width - borderSize, borderSize, borderSize, height - borderSize * 2); // right

        context.restore();
    },

    handleMouseDown: function handleMouseDown() {
        this.setState({
            drag: true,
            mx: null,
            my: null
        });
    },
    handleMouseUp: function handleMouseUp() {
        if (this.state.drag) {
            this.setState({ drag: false });
        }
    },

    handleMouseMove: function handleMouseMove(e) {
        if (false == this.state.drag) {
            return;
        }

        var imageState = this.state.image;
        var lastX = imageState.x;
        var lastY = imageState.y;

        var mousePositionX = isTouchDevice ? event.targetTouches[0].pageX : e.clientX;
        var mousePositionY = isTouchDevice ? event.targetTouches[0].pageY : e.clientY;

        var newState = { mx: mousePositionX, my: mousePositionY, image: imageState };

        if (this.state.mx && this.state.my) {
            var xDiff = this.state.mx - mousePositionX;
            var yDiff = this.state.my - mousePositionY;

            imageState.y = this.getBoundedY(lastY - yDiff, this.props.scale);
            imageState.x = this.getBoundedX(lastX - xDiff, this.props.scale);
        }

        this.setState(newState);
    },

    squeeze: function squeeze(props) {
        var imageState = this.state.image;
        imageState.y = this.getBoundedY(imageState.y, props.scale);
        imageState.x = this.getBoundedX(imageState.x, props.scale);
        this.setState({ image: imageState });
    },

    getBoundedX: function getBoundedX(x, scale) {
        var image = this.state.image;
        var dimensions = this.getDimensions();
        var widthDiff = Math.ceil((image.width * scale - image.width) / 2);
        var rightPoint = Math.ceil(-image.width * scale + dimensions.width + dimensions.border);
        var leftPoint = dimensions.border;

        var result;
        if (x - widthDiff >= dimensions.border) result = dimensions.border + widthDiff;
        if (x < rightPoint) result = rightPoint;
        if (x > leftPoint) result = leftPoint;

        return result || x;
    },

    getBoundedY: function getBoundedY(y, scale) {
        var image = this.state.image;
        var dimensions = this.getDimensions();
        var heightDiff = Math.ceil((image.height * scale - image.height) / 2);
        var bottomPoint = Math.ceil(-image.height * scale + dimensions.height + dimensions.border);
        var topPoint = dimensions.border;

        var result;
        if (y - heightDiff >= dimensions.border) result = dimensions.border + heightDiff;
        if (y < bottomPoint) result = bottomPoint;
        if (y > topPoint) result = topPoint;

        return result || y;
    },

    handleDragOver: function handleDragOver(e) {
        e.preventDefault();
    },

    handleDrop: function handleDrop(e) {
        e.stopPropagation();
        e.preventDefault();

        var reader = new FileReader();
        reader.onload = this.handleUploadReady;
        reader.readAsDataURL(e.dataTransfer.files[0]);
    },

    handleUploadReady: function handleUploadReady(e) {
        this.loadImage(e.target.result);
    },

    render: function render() {
        var attributes = {
            width: this.getDimensions().canvas.width,
            height: this.getDimensions().canvas.height,
            style: this.props.style
        };

        attributes[deviceEvents.react.down] = this.handleMouseDown;
        attributes[deviceEvents.react.drag] = this.handleDragOver;
        attributes[deviceEvents.react.drop] = this.handleDrop;

        return React.createElement('canvas', attributes);
    }

});

module.exports = ReactAvatarEditor;
<commit_msg>Turn HQ mode into a boolean property option<commit_after>'use strict';

var React = require('react');

var isTouchDevice = 'ontouchstart' in window || navigator.msMaxTouchPoints > 0;
var draggableEvents = {
    mobile: {
        react: {
            down: 'onTouchStart',
            drag: 'onTouchMove',
            drop: 'onTouchEnd',
            move: 'onTouchMove',
            up: 'onTouchUp'
        },
        native: {
            down: 'touchstart',
            drag: 'touchmove',
            drop: 'touchend',
            move: 'touchmove',
            up: 'touchup'
        }
    },
    desktop: {
        react: {
            down: 'onMouseDown',
            drag: 'onDragOver',
            drop: 'onDrop',
            move: 'onMouseMove',
            up: 'onMouseUp'
        },
        native: {
            down: 'mousedown',
            drag: 'dragStart',
            drop: 'drop',
            move: 'mousemove',
            up: 'mouseup'
        }
    }
};
var deviceEvents = isTouchDevice ? draggableEvents.mobile : draggableEvents.desktop;

var ReactAvatarEditor = React.createClass({
    displayName: 'ReactAvatarEditor',

    propTypes: {
        scale: React.PropTypes.number,
        image: React.PropTypes.string,
        border: React.PropTypes.number,
        width: React.PropTypes.number,
        height: React.PropTypes.number,
        color: React.PropTypes.arrayOf(React.PropTypes.number),
        onImageReady: React.PropTypes.func,
        style: React.PropTypes.object,
        highQuality: React.PropTypes.bool
    },

    getDefaultProps: function getDefaultProps() {
        return {
            scale: 1,
            border: 25,
            width: 200,
            height: 200,
            color: [0, 0, 0, 0.5],
            onImageReady: function onImageReady() {},
            style: {},
            highQuality: false
        };
    },

    getInitialState: function getInitialState() {
        return {
            drag: false,
            my: null,
            mx: null,
            image: {
                x: 0,
                y: 0
            }
        };
    },

    getDimensions: function getDimensions() {
        return {
            width: this.props.width,
            height: this.props.height,
            border: this.props.border,
            canvas: {
                width: this.props.width + this.props.border * 2,
                height: this.props.height + this.props.border * 2
            }
        };
    },

    getImage: function getImage(type, quality) {
        var dom = document.createElement('canvas');
        var context = dom.getContext('2d');
        var dimensions = this.getDimensions();

        dom.width = dimensions.width;
        dom.height = dimensions.height;

        context.globalCompositeOperation = 'destination-over';

        var imageState = this.state.image;

        this.paintImage(context, {
            resource: imageState.resource,
            x: imageState.x - dimensions.border,
            y: imageState.y - dimensions.border,
            width: imageState.width,
            height: imageState.height
        });

        return dom.toDataURL(type, quality);
    },

    isDataURL: function isDataURL(str) {
        var regex = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
        return !!str.match(regex);
    },

    loadImage: function loadImage(imageURL) {
        var imageObj = new Image();
        imageObj.onload = this.handleImageReady.bind(this, imageObj);
        if (!this.isDataURL(imageURL)) imageObj.crossOrigin = 'anonymous';
        imageObj.src = imageURL;
    },

    componentDidMount: function componentDidMount() {
        var context = this.getDOMNode().getContext('2d');
        if (this.props.image) {
            this.loadImage(this.props.image);
        }
        this.paint(context);
        document && document.addEventListener(deviceEvents.native.move, this.handleMouseMove, false);
        document && document.addEventListener(deviceEvents.native.up, this.handleMouseUp, false);

        if (isTouchDevice) React.initializeTouchEvents(true);
    },

    componentWillUnmount: function componentWillUnmount() {
        document && document.removeEventListener(deviceEvents.native.move, this.handleMouseMove, false);
        document && document.removeEventListener(deviceEvents.native.up, this.handleMouseUp, false);
    },

    componentDidUpdate: function componentDidUpdate() {
        var context = this.getDOMNode().getContext('2d');
        context.clearRect(0, 0, this.getDimensions().canvas.width, this.getDimensions().canvas.height);
        this.paint(context);
        this.paintImage(context, this.state.image);
    },

    handleImageReady: function handleImageReady(image) {
        var imageState = this.getInitialSize(image.width, image.height);
        imageState.resource = image;
        imageState.x = this.props.border;
        imageState.y = this.props.border;
        this.setState({ drag: false, image: imageState }, this.props.onImageReady);
    },

    getInitialSize: function getInitialSize(width, height) {
        var newHeight, newWidth, dimensions, canvasRatio, imageRatio;

        dimensions = this.getDimensions();

        canvasRatio = dimensions.height / dimensions.width;
        imageRatio = height / width;

        if (canvasRatio > imageRatio) {
            newHeight = this.getDimensions().height;
            newWidth = width * (newHeight / height);
        } else {
            newWidth = this.getDimensions().width;
            newHeight = height * (newWidth / width);
        }

        return {
            height: newHeight,
            width: newWidth
        };
    },

    componentWillReceiveProps: function componentWillReceiveProps(newProps) {
        if (this.props.image != newProps.image) {
            this.loadImage(newProps.image);
        }
        if (this.props.scale != newProps.scale) {
            this.squeeze(newProps);
        }
    },

    paintImage: function paintImage(context, image) {
        if (image.resource) {
            var position = this.calculatePosition(image);
            context.save();
            context.globalCompositeOperation = 'destination-over';

            if (this.props.highQuality) {
                var scale = image.resource.width / position.width;

                var dimensions = this.getDimensions();
                context.canvas.width = dimensions.width * scale;
                context.canvas.height = dimensions.height * scale;

                var x = image.x * scale;
                var y = image.y * scale;

                context.drawImage(image.resource, x, y, image.resource.width, image.resource.height);
            } else {
                context.drawImage(image.resource, image.x, image.y, position.width, position.height);
            }

            context.restore();
        }
    },

    calculatePosition: function calculatePosition(image) {
        image = image || this.state.image;
        var x,
            y,
            width,
            height,
            dimensions = this.getDimensions();

        width = image.width * this.props.scale;
        height = image.height * this.props.scale;
        var widthDiff = (width - image.width) / 2;
        var heightDiff = (height - image.height) / 2;
        x = image.x - widthDiff;
        y = image.y - heightDiff;

        // top and left border bounding
        x = Math.min(x, dimensions.border);
        y = Math.min(y, dimensions.border);

        // right and bottom
        var fromBottom = height + (y - dimensions.border);
        y = fromBottom > dimensions.height ? y : y + (dimensions.height - fromBottom);
        var fromRight = width + (x - dimensions.border);
        x = fromRight > dimensions.width ? x : x + (dimensions.width - fromRight);

        return {
            x: x,
            y: y,
            height: height,
            width: width
        };
    },

    paint: function paint(context) {
        context.save();
        context.translate(0, 0);
        context.fillStyle = 'rgba(' + this.props.color.slice(0, 4).join(',') + ')';

        var dimensions = this.getDimensions();

        var borderSize = dimensions.border;
        var height = dimensions.canvas.height;
        var width = dimensions.canvas.width;

        context.fillRect(0, 0, width, borderSize); // top
        context.fillRect(0, height - borderSize, width, borderSize); // bottom
        context.fillRect(0, borderSize, borderSize, height - borderSize * 2); // left
        context.fillRect(width - borderSize, borderSize, borderSize, height - borderSize * 2); // right

        context.restore();
    },

    handleMouseDown: function handleMouseDown() {
        this.setState({
            drag: true,
            mx: null,
            my: null
        });
    },
    handleMouseUp: function handleMouseUp() {
        if (this.state.drag) {
            this.setState({ drag: false });
        }
    },

    handleMouseMove: function handleMouseMove(e) {
        if (false == this.state.drag) {
            return;
        }

        var imageState = this.state.image;
        var lastX = imageState.x;
        var lastY = imageState.y;

        var mousePositionX = isTouchDevice ? event.targetTouches[0].pageX : e.clientX;
        var mousePositionY = isTouchDevice ? event.targetTouches[0].pageY : e.clientY;

        var newState = { mx: mousePositionX, my: mousePositionY, image: imageState };

        if (this.state.mx && this.state.my) {
            var xDiff = this.state.mx - mousePositionX;
            var yDiff = this.state.my - mousePositionY;

            imageState.y = this.getBoundedY(lastY - yDiff, this.props.scale);
            imageState.x = this.getBoundedX(lastX - xDiff, this.props.scale);
        }

        this.setState(newState);
    },

    squeeze: function squeeze(props) {
        var imageState = this.state.image;
        imageState.y = this.getBoundedY(imageState.y, props.scale);
        imageState.x = this.getBoundedX(imageState.x, props.scale);
        this.setState({ image: imageState });
    },

    getBoundedX: function getBoundedX(x, scale) {
        var image = this.state.image;
        var dimensions = this.getDimensions();
        var widthDiff = Math.ceil((image.width * scale - image.width) / 2);
        var rightPoint = Math.ceil(-image.width * scale + dimensions.width + dimensions.border);
        var leftPoint = dimensions.border;

        var result;
        if (x - widthDiff >= dimensions.border) result = dimensions.border + widthDiff;
        if (x < rightPoint) result = rightPoint;
        if (x > leftPoint) result = leftPoint;

        return result || x;
    },

    getBoundedY: function getBoundedY(y, scale) {
        var image = this.state.image;
        var dimensions = this.getDimensions();
        var heightDiff = Math.ceil((image.height * scale - image.height) / 2);
        var bottomPoint = Math.ceil(-image.height * scale + dimensions.height + dimensions.border);
        var topPoint = dimensions.border;

        var result;
        if (y - heightDiff >= dimensions.border) result = dimensions.border + heightDiff;
        if (y < bottomPoint) result = bottomPoint;
        if (y > topPoint) result = topPoint;

        return result || y;
    },

    handleDragOver: function handleDragOver(e) {
        e.preventDefault();
    },

    handleDrop: function handleDrop(e) {
        e.stopPropagation();
        e.preventDefault();

        var reader = new FileReader();
        reader.onload = this.handleUploadReady;
        reader.readAsDataURL(e.dataTransfer.files[0]);
    },

    handleUploadReady: function handleUploadReady(e) {
        this.loadImage(e.target.result);
    },

    render: function render() {
        var attributes = {
            width: this.getDimensions().canvas.width,
            height: this.getDimensions().canvas.height,
            style: this.props.style
        };

        attributes[deviceEvents.react.down] = this.handleMouseDown;
        attributes[deviceEvents.react.drag] = this.handleDragOver;
        attributes[deviceEvents.react.drop] = this.handleDrop;

        return React.createElement('canvas', attributes);
    }

});

module.exports = ReactAvatarEditor;
<|endoftext|>


<commit_before>enyo.kind({
	name: "moon.sample.CalendarSample",
	classes: "moon enyo-unselectable enyo-fit",
	kind: "FittableColumns",
	components: [
		{components: [
			{kind: "moon.Calendar", name: "calendar", onChange: "changed"}
		]},
		{kind: "FittableRows", fit: true, components: [
			{kind: "moon.Scroller", fit:true, components: [
				{kind:"moon.Divider", content:"Set value:"},
				{classes:"moon-hspacing", components: [
					{kind: "moon.InputDecorator", classes: "moon-2h", components: [
						{kind: "moon.Input", name:"yearInput", placeholder: "Year"}
					]},
					{kind: "moon.InputDecorator", classes: "moon-2h", components: [
						{kind: "moon.Input", name:"monthInput", placeholder: "Month"}
					]},
					{kind: "moon.InputDecorator", classes: "moon-2h", components: [
						{kind: "moon.Input", name:"dayInput", placeholder: "Day"}
					]}
				]},
				{classes:"moon-hspacing", components: [
					{kind: "moon.Button", small:true, content:"Set Date", ontap:"setDate"},
					{kind: "moon.Button", small:true, content:"Reset to Current", ontap:"resetDate"}
				]},
				{classes:"moon-1v"},
				{classes:"moon-7h", components: [
					{kind: "moon.DatePicker", name: "picker", noneText: "Pick a Date", content: "Pick a Date"},
					{kind: "moon.ExpandablePicker", name:"localePicker", noneText: "No Language Selected", content: "Choose Locale", onChange: "setLocale", components: [
						{content: "en-US", active:true}, //United States, firstDayOfWeek: 0
						{content: "th-TH"}, //Thailand
						{content: "en-CA"}, //Canada, firstDayOfWeek: 0
						{content: "ko-KO"}, //Korea, firstDayOfWeek: 1
						{content: "und-AE"}, //United Arab Emirates, firstDayOfWeek: 6
						{content: "und-AG"}, //Antigua and Barbuda, firstDayOfWeek: 0
						{content: "und-CA"}, //Canada, firstDayOfWeek: 0
						{content: "it-CH"}, //Italian
						{content: "en-MX"},
						{content: "de-DE"}, // Germany, firstDayOfWeek: 1
						{content: "fr-FR"}, // France, firstDayOfWeek: 1
						{content: "fr-CA"},
						{content: "it-IT"}, // Italy, firstDayOfWeek: 1
						{content: "es-ES"}, // Spain, firstDayOfWeek: 1
						{content: "es-MX"}
					]},
					{name: 'dowLengthPicker', kind: "moon.ExpandablePicker", content: "Choose DOW Label Length", onChange: "setLabelLength", components: [
						{content: "short", active: true},
						{content: "medium"},
						{content: "long"},
						{content: "full"}
					]},
					{name: 'dowLabelClass', kind: "moon.ExpandablePicker", content: "Choose DOW Label Class", onChange: "setLabelStyle", components: [
						{content: "Default", active: true, className:""},
						{content: "Divider", className:"moon-divider moon-divider-text"},
						{content: "Smaller font", className: "moon-calendar-picker-day small"}
					]}
				]}
			]},
			{kind: "moon.Divider", content: "Result"},
			{kind: "moon.BodyText", name: "result", content: "No change yet"}
		]}
	],
	bindings: [
		{from: ".$.calendar.value", to:".$.picker.value", oneWay:false}
	],
	create: function(){
		this.inherited(arguments);
		if (!window.ilib) {
			this.$.localePicker.hide();
			this.$.dowLengthPicker.hide();
			this.log("iLib not present -- hiding locale & dow length picker");
		} else {
			this.df = new ilib.DateFmt({
				type: "datetime",
				time: "hmsa",
				date: "dmy",
				useNative: false,
				length: "short"
			});
		}
	},

	updateCurrentString: function (date) {
		var formatted = window.ilib ? this.df.format(date) : date.toDateString();
		this.$.result.setContent("Current Date" + " changed to " + formatted);
	},

	setLocale: function(inSender, inEvent){
		if (ilib) {
			ilib.setLocale(inEvent.selected.content);
			this.$.calendar.setLocale(inEvent.selected.content);
			this.$.picker.setLocale(inEvent.selected.content);
			this.df = new ilib.DateFmt({
				type: "datetime",
				time: "hmsa",
				date: "dmy",
				useNative: false,
				length: this.$.dowLengthPicker.selected.content
			});
			this.updateCurrentString(this.$.calendar.getValue());
		}
		return true;
	},
	setLabelLength: function(inSender, inEvent){
		if (inEvent.content){
			this.$.calendar.setDayOfWeekLength(inEvent.content);
			if (ilib) {
				this.df = new ilib.DateFmt({
					type: "datetime",
					time: "hmsa",
					date: "dmy",
					useNative: false,
					length: inEvent.content
				});
			}
			this.updateCurrentString(this.$.calendar.getValue());
			this.removeLabelItem(this.$.dowLabelClass, inEvent, 'Divider', 'full');
		}
		return true;
	},
	setLabelStyle: function(inSender, inEvent){
		if (inEvent.content){
			this.$.calendar.setDayOfWeekClasses(inEvent.selected.className);
			this.removeLabelItem(this.$.dowLengthPicker, inEvent, 'full', 'Divider');
		}
		return true;
	},
	removeLabelItem: function (inControl, inEvent, inLabelName1, inLabelName2) {
		var i,
			c = inControl.getClientControls();
		for (i = 0; i < c.length; i++) {
			if (c[i].content == inLabelName1) {
				c[i].addRemoveClass("moon-calendar-dow-lable-nodisplay", Boolean(inEvent.content == inLabelName2));
			}
		}
	},
	changed: function(inSender, inEvent) {
		if (this.$.result && inEvent.value) {
			this.updateCurrentString(inEvent.value);
		}
	},
	setDate: function(inSender, inEvent){
		var year = isNaN(parseInt(this.$.yearInput.getValue(), 0)) ? this.$.picker.value.getFullYear() : parseInt(this.$.yearInput.getValue(), 0);
		var month = isNaN(parseInt(this.$.monthInput.getValue(), 0)) ? this.$.picker.value.getMonth() : parseInt(this.$.monthInput.getValue(), 0) - 1;
		var day = isNaN(parseInt(this.$.dayInput.getValue(), 0)) ? this.$.picker.value.getDate() : parseInt(this.$.dayInput.getValue(), 0);
		this.$.calendar.setValue(new Date(year, month, day));
	},
	resetDate: function() {
		this.$.calendar.setValue(null);
	}
});<commit_msg>BHV-14088: Add fa-IR locale to sample.<commit_after>enyo.kind({
	name: "moon.sample.CalendarSample",
	classes: "moon enyo-unselectable enyo-fit",
	kind: "FittableColumns",
	components: [
		{components: [
			{kind: "moon.Calendar", name: "calendar", onChange: "changed"}
		]},
		{kind: "FittableRows", fit: true, components: [
			{kind: "moon.Scroller", fit:true, components: [
				{kind:"moon.Divider", content:"Set value:"},
				{classes:"moon-hspacing", components: [
					{kind: "moon.InputDecorator", classes: "moon-2h", components: [
						{kind: "moon.Input", name:"yearInput", placeholder: "Year"}
					]},
					{kind: "moon.InputDecorator", classes: "moon-2h", components: [
						{kind: "moon.Input", name:"monthInput", placeholder: "Month"}
					]},
					{kind: "moon.InputDecorator", classes: "moon-2h", components: [
						{kind: "moon.Input", name:"dayInput", placeholder: "Day"}
					]}
				]},
				{classes:"moon-hspacing", components: [
					{kind: "moon.Button", small:true, content:"Set Date", ontap:"setDate"},
					{kind: "moon.Button", small:true, content:"Reset to Current", ontap:"resetDate"}
				]},
				{classes:"moon-1v"},
				{classes:"moon-7h", components: [
					{kind: "moon.DatePicker", name: "picker", noneText: "Pick a Date", content: "Pick a Date"},
					{kind: "moon.ExpandablePicker", name:"localePicker", noneText: "No Language Selected", content: "Choose Locale", onChange: "setLocale", components: [
						{content: "en-US", active:true}, //United States, firstDayOfWeek: 0
						{content: "th-TH"}, //Thailand
						{content: "fa-IR"}, // Iran, persian calendar
						{content: "en-CA"}, //Canada, firstDayOfWeek: 0
						{content: "ko-KO"}, //Korea, firstDayOfWeek: 1
						{content: "und-AE"}, //United Arab Emirates, firstDayOfWeek: 6
						{content: "und-AG"}, //Antigua and Barbuda, firstDayOfWeek: 0
						{content: "und-CA"}, //Canada, firstDayOfWeek: 0
						{content: "it-CH"}, //Italian
						{content: "en-MX"},
						{content: "de-DE"}, // Germany, firstDayOfWeek: 1
						{content: "fr-FR"}, // France, firstDayOfWeek: 1
						{content: "fr-CA"},
						{content: "it-IT"}, // Italy, firstDayOfWeek: 1
						{content: "es-ES"}, // Spain, firstDayOfWeek: 1
						{content: "es-MX"}
					]},
					{name: 'dowLengthPicker', kind: "moon.ExpandablePicker", content: "Choose DOW Label Length", onChange: "setLabelLength", components: [
						{content: "short", active: true},
						{content: "medium"},
						{content: "long"},
						{content: "full"}
					]},
					{name: 'dowLabelClass', kind: "moon.ExpandablePicker", content: "Choose DOW Label Class", onChange: "setLabelStyle", components: [
						{content: "Default", active: true, className:""},
						{content: "Divider", className:"moon-divider moon-divider-text"},
						{content: "Smaller font", className: "moon-calendar-picker-day small"}
					]}
				]}
			]},
			{kind: "moon.Divider", content: "Result"},
			{kind: "moon.BodyText", name: "result", content: "No change yet"}
		]}
	],
	bindings: [
		{from: ".$.calendar.value", to:".$.picker.value", oneWay:false}
	],
	create: function(){
		this.inherited(arguments);
		if (!window.ilib) {
			this.$.localePicker.hide();
			this.$.dowLengthPicker.hide();
			this.log("iLib not present -- hiding locale & dow length picker");
		} else {
			this.df = new ilib.DateFmt({
				type: "datetime",
				time: "hmsa",
				date: "dmy",
				useNative: false,
				length: "short"
			});
		}
	},

	updateCurrentString: function (date) {
		var formatted = window.ilib ? this.df.format(date) : date.toDateString();
		this.$.result.setContent("Current Date" + " changed to " + formatted);
	},

	setLocale: function(inSender, inEvent){
		if (ilib) {
			ilib.setLocale(inEvent.selected.content);
			this.$.calendar.setLocale(inEvent.selected.content);
			this.$.picker.setLocale(inEvent.selected.content);
			this.df = new ilib.DateFmt({
				type: "datetime",
				time: "hmsa",
				date: "dmy",
				useNative: false,
				length: this.$.dowLengthPicker.selected.content
			});
			this.updateCurrentString(this.$.calendar.getValue());
		}
		return true;
	},
	setLabelLength: function(inSender, inEvent){
		if (inEvent.content){
			this.$.calendar.setDayOfWeekLength(inEvent.content);
			if (ilib) {
				this.df = new ilib.DateFmt({
					type: "datetime",
					time: "hmsa",
					date: "dmy",
					useNative: false,
					length: inEvent.content
				});
			}
			this.updateCurrentString(this.$.calendar.getValue());
			this.removeLabelItem(this.$.dowLabelClass, inEvent, 'Divider', 'full');
		}
		return true;
	},
	setLabelStyle: function(inSender, inEvent){
		if (inEvent.content){
			this.$.calendar.setDayOfWeekClasses(inEvent.selected.className);
			this.removeLabelItem(this.$.dowLengthPicker, inEvent, 'full', 'Divider');
		}
		return true;
	},
	removeLabelItem: function (inControl, inEvent, inLabelName1, inLabelName2) {
		var i,
			c = inControl.getClientControls();
		for (i = 0; i < c.length; i++) {
			if (c[i].content == inLabelName1) {
				c[i].addRemoveClass("moon-calendar-dow-lable-nodisplay", Boolean(inEvent.content == inLabelName2));
			}
		}
	},
	changed: function(inSender, inEvent) {
		if (this.$.result && inEvent.value) {
			this.updateCurrentString(inEvent.value);
		}
	},
	setDate: function(inSender, inEvent){
		var year = isNaN(parseInt(this.$.yearInput.getValue(), 0)) ? this.$.picker.value.getFullYear() : parseInt(this.$.yearInput.getValue(), 0);
		var month = isNaN(parseInt(this.$.monthInput.getValue(), 0)) ? this.$.picker.value.getMonth() : parseInt(this.$.monthInput.getValue(), 0) - 1;
		var day = isNaN(parseInt(this.$.dayInput.getValue(), 0)) ? this.$.picker.value.getDate() : parseInt(this.$.dayInput.getValue(), 0);
		this.$.calendar.setValue(new Date(year, month, day));
	},
	resetDate: function() {
		this.$.calendar.setValue(null);
	}
});<|endoftext|>


<commit_before>/**@constructor*/
BaseStemmer = function() {
    this.setCurrent = function(value) {
        this.current = value;
	this.cursor = 0;
	this.limit = this.current.length;
	this.limit_backward = 0;
	this.bra = this.cursor;
	this.ket = this.limit;
    };

    this.getCurrent = function() {
        return this.current;
    };

    this.copy_from = function(other) {
	this.current          = other.current;
	this.cursor           = other.cursor;
	this.limit            = other.limit;
	this.limit_backward   = other.limit_backward;
	this.bra              = other.bra;
	this.ket              = other.ket;
    };

    this.in_grouping = function(s, min, max) {
	if (this.cursor >= this.limit) return false;
	var ch = this.current.charCodeAt(this.cursor);
	if (ch > max || ch < min) return false;
	ch -= min;
	if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return false;
	this.cursor++;
	return true;
    };

    this.in_grouping_b = function(s, min, max) {
	if (this.cursor <= this.limit_backward) return false;
	var ch = this.current.charCodeAt(this.cursor - 1);
	if (ch > max || ch < min) return false;
	ch -= min;
	if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return false;
	this.cursor--;
	return true;
    };

    this.out_grouping = function(s, min, max) {
	if (this.cursor >= this.limit) return false;
	var ch = this.current.charCodeAt(this.cursor);
	if (ch > max || ch < min) {
	    this.cursor++;
	    return true;
	}
	ch -= min;
	if ((s[ch >>> 3] & (0X1 << (ch & 0x7))) == 0) {
	    this.cursor++;
	    return true;
	}
	return false;
    };

    this.out_grouping_b = function(s, min, max) {
	if (this.cursor <= this.limit_backward) return false;
	var ch = this.current.charCodeAt(this.cursor - 1);
	if (ch > max || ch < min) {
	    this.cursor--;
	    return true;
	}
	ch -= min;
	if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) {
	    this.cursor--;
	    return true;
	}
	return false;
    };

    this.eq_s = function(s)
    {
	if (this.limit - this.cursor < s.length) return false;
        if (this.current.slice(this.cursor, this.cursor + s.length) != s)
        {
            return false;
        }
	this.cursor += s.length;
	return true;
    };

    this.eq_s_b = function(s)
    {
	if (this.cursor - this.limit_backward < s.length) return false;
        if (this.current.slice(this.cursor - s.length, this.cursor) != s)
        {
            return false;
        }
	this.cursor -= s.length;
	return true;
    };

    /** @return {number} */ this.find_among = function(v)
    {
	var i = 0;
	var j = v.length;

	var c = this.cursor;
	var l = this.limit;

	var common_i = 0;
	var common_j = 0;

	var first_key_inspected = false;

	while (true)
        {
	    var k = i + ((j - i) >>> 1);
	    var diff = 0;
	    var common = common_i < common_j ? common_i : common_j; // smaller
	    // w[0]: string, w[1]: substring_i, w[2]: result, w[3]: function (optional)
	    var w = v[k];
	    var i2;
	    for (i2 = common; i2 < w[0].length; i2++)
            {
		if (c + common == l)
                {
		    diff = -1;
		    break;
		}
		diff = this.current.charCodeAt(c + common) - w[0].charCodeAt(i2);
		if (diff != 0) break;
		common++;
	    }
	    if (diff < 0)
            {
		j = k;
		common_j = common;
	    }
            else
            {
		i = k;
		common_i = common;
	    }
	    if (j - i <= 1)
            {
		if (i > 0) break; // v->s has been inspected
		if (j == i) break; // only one item in v

		// - but now we need to go round once more to get
		// v->s inspected. This looks messy, but is actually
		// the optimal approach.

		if (first_key_inspected) break;
		first_key_inspected = true;
	    }
	}
	while (true)
        {
	    var w = v[i];
	    if (common_i >= w[0].length)
            {
		this.cursor = c + w[0].length;
		if (w.length < 4) return w[2];
		var res = w[3](this);
		this.cursor = c + w[0].length;
		if (res) return w[2];
	    }
	    i = w[1];
	    if (i < 0) return 0;
	}
    };

    // find_among_b is for backwards processing. Same comments apply
    this.find_among_b = function(v)
    {
	var i = 0;
	var j = v.length

	var c = this.cursor;
	var lb = this.limit_backward;

	var common_i = 0;
	var common_j = 0;

	var first_key_inspected = false;

	while (true)
        {
	    var k = i + ((j - i) >> 1);
	    var diff = 0;
	    var common = common_i < common_j ? common_i : common_j;
	    var w = v[k];
	    var i2;
	    for (i2 = w[0].length - 1 - common; i2 >= 0; i2--)
            {
		if (c - common == lb)
                {
		    diff = -1;
		    break;
		}
		diff = this.current.charCodeAt(c - 1 - common) - w[0].charCodeAt(i2);
		if (diff != 0) break;
		common++;
	    }
	    if (diff < 0)
            {
		j = k;
		common_j = common;
	    }
            else
            {
		i = k;
		common_i = common;
	    }
	    if (j - i <= 1)
            {
		if (i > 0) break;
		if (j == i) break;
		if (first_key_inspected) break;
		first_key_inspected = true;
	    }
	}
	while (true)
        {
	    var w = v[i];
	    if (common_i >= w[0].length)
            {
		this.cursor = c - w[0].length;
		if (w.length < 4) return w[2];
		var res = w[3](this);
		this.cursor = c - w[0].length;
		if (res) return w[2];
	    }
	    i = w[1];
	    if (i < 0) return 0;
	}
    };

    /* to replace chars between c_bra and c_ket in this.current by the
     * chars in s.
     */
    this.replace_s = function(c_bra, c_ket, s)
    {
	var adjustment = s.length - (c_ket - c_bra);
	this.current = this.current.slice(0, c_bra) + s + this.current.slice(c_ket);
	this.limit += adjustment;
	if (this.cursor >= c_ket) this.cursor += adjustment;
	else if (this.cursor > c_bra) this.cursor = c_bra;
	return adjustment;
    };

    this.slice_check = function()
    {
        if (this.bra < 0 ||
            this.bra > this.ket ||
            this.ket > this.limit ||
            this.limit > this.current.length)
        {
            return false;
        }
        return true;
    };

    this.slice_from = function(s)
    {
        var result = false;
	if (this.slice_check())
        {
	    this.replace_s(this.bra, this.ket, s);
            result = true;
        }
        return result;
    };

    this.slice_del = function()
    {
	return this.slice_from("");
    };

    this.insert = function(c_bra, c_ket, s)
    {
        var adjustment = this.replace_s(c_bra, c_ket, s);
	if (c_bra <= this.bra) this.bra += adjustment;
	if (c_bra <= this.ket) this.ket += adjustment;
    };

    this.slice_to = function()
    {
        var result = '';
	if (this.slice_check())
        {
            result = this.current.slice(this.bra, this.ket);
        }
        return result;
    };

    this.assign_to = function()
    {
        return this.current.slice(0, this.limit);
    };
};
<commit_msg>[js] Use do/while loop for clearer code<commit_after>/**@constructor*/
BaseStemmer = function() {
    this.setCurrent = function(value) {
        this.current = value;
	this.cursor = 0;
	this.limit = this.current.length;
	this.limit_backward = 0;
	this.bra = this.cursor;
	this.ket = this.limit;
    };

    this.getCurrent = function() {
        return this.current;
    };

    this.copy_from = function(other) {
	this.current          = other.current;
	this.cursor           = other.cursor;
	this.limit            = other.limit;
	this.limit_backward   = other.limit_backward;
	this.bra              = other.bra;
	this.ket              = other.ket;
    };

    this.in_grouping = function(s, min, max) {
	if (this.cursor >= this.limit) return false;
	var ch = this.current.charCodeAt(this.cursor);
	if (ch > max || ch < min) return false;
	ch -= min;
	if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return false;
	this.cursor++;
	return true;
    };

    this.in_grouping_b = function(s, min, max) {
	if (this.cursor <= this.limit_backward) return false;
	var ch = this.current.charCodeAt(this.cursor - 1);
	if (ch > max || ch < min) return false;
	ch -= min;
	if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return false;
	this.cursor--;
	return true;
    };

    this.out_grouping = function(s, min, max) {
	if (this.cursor >= this.limit) return false;
	var ch = this.current.charCodeAt(this.cursor);
	if (ch > max || ch < min) {
	    this.cursor++;
	    return true;
	}
	ch -= min;
	if ((s[ch >>> 3] & (0X1 << (ch & 0x7))) == 0) {
	    this.cursor++;
	    return true;
	}
	return false;
    };

    this.out_grouping_b = function(s, min, max) {
	if (this.cursor <= this.limit_backward) return false;
	var ch = this.current.charCodeAt(this.cursor - 1);
	if (ch > max || ch < min) {
	    this.cursor--;
	    return true;
	}
	ch -= min;
	if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) {
	    this.cursor--;
	    return true;
	}
	return false;
    };

    this.eq_s = function(s)
    {
	if (this.limit - this.cursor < s.length) return false;
        if (this.current.slice(this.cursor, this.cursor + s.length) != s)
        {
            return false;
        }
	this.cursor += s.length;
	return true;
    };

    this.eq_s_b = function(s)
    {
	if (this.cursor - this.limit_backward < s.length) return false;
        if (this.current.slice(this.cursor - s.length, this.cursor) != s)
        {
            return false;
        }
	this.cursor -= s.length;
	return true;
    };

    /** @return {number} */ this.find_among = function(v)
    {
	var i = 0;
	var j = v.length;

	var c = this.cursor;
	var l = this.limit;

	var common_i = 0;
	var common_j = 0;

	var first_key_inspected = false;

	while (true)
        {
	    var k = i + ((j - i) >>> 1);
	    var diff = 0;
	    var common = common_i < common_j ? common_i : common_j; // smaller
	    // w[0]: string, w[1]: substring_i, w[2]: result, w[3]: function (optional)
	    var w = v[k];
	    var i2;
	    for (i2 = common; i2 < w[0].length; i2++)
            {
		if (c + common == l)
                {
		    diff = -1;
		    break;
		}
		diff = this.current.charCodeAt(c + common) - w[0].charCodeAt(i2);
		if (diff != 0) break;
		common++;
	    }
	    if (diff < 0)
            {
		j = k;
		common_j = common;
	    }
            else
            {
		i = k;
		common_i = common;
	    }
	    if (j - i <= 1)
            {
		if (i > 0) break; // v->s has been inspected
		if (j == i) break; // only one item in v

		// - but now we need to go round once more to get
		// v->s inspected. This looks messy, but is actually
		// the optimal approach.

		if (first_key_inspected) break;
		first_key_inspected = true;
	    }
	}
	do {
	    var w = v[i];
	    if (common_i >= w[0].length)
            {
		this.cursor = c + w[0].length;
		if (w.length < 4) return w[2];
		var res = w[3](this);
		this.cursor = c + w[0].length;
		if (res) return w[2];
	    }
	    i = w[1];
	} while (i >= 0);
	return 0;
    };

    // find_among_b is for backwards processing. Same comments apply
    this.find_among_b = function(v)
    {
	var i = 0;
	var j = v.length

	var c = this.cursor;
	var lb = this.limit_backward;

	var common_i = 0;
	var common_j = 0;

	var first_key_inspected = false;

	while (true)
        {
	    var k = i + ((j - i) >> 1);
	    var diff = 0;
	    var common = common_i < common_j ? common_i : common_j;
	    var w = v[k];
	    var i2;
	    for (i2 = w[0].length - 1 - common; i2 >= 0; i2--)
            {
		if (c - common == lb)
                {
		    diff = -1;
		    break;
		}
		diff = this.current.charCodeAt(c - 1 - common) - w[0].charCodeAt(i2);
		if (diff != 0) break;
		common++;
	    }
	    if (diff < 0)
            {
		j = k;
		common_j = common;
	    }
            else
            {
		i = k;
		common_i = common;
	    }
	    if (j - i <= 1)
            {
		if (i > 0) break;
		if (j == i) break;
		if (first_key_inspected) break;
		first_key_inspected = true;
	    }
	}
	do {
	    var w = v[i];
	    if (common_i >= w[0].length)
            {
		this.cursor = c - w[0].length;
		if (w.length < 4) return w[2];
		var res = w[3](this);
		this.cursor = c - w[0].length;
		if (res) return w[2];
	    }
	    i = w[1];
	} while (i >= 0);
	return 0;
    };

    /* to replace chars between c_bra and c_ket in this.current by the
     * chars in s.
     */
    this.replace_s = function(c_bra, c_ket, s)
    {
	var adjustment = s.length - (c_ket - c_bra);
	this.current = this.current.slice(0, c_bra) + s + this.current.slice(c_ket);
	this.limit += adjustment;
	if (this.cursor >= c_ket) this.cursor += adjustment;
	else if (this.cursor > c_bra) this.cursor = c_bra;
	return adjustment;
    };

    this.slice_check = function()
    {
        if (this.bra < 0 ||
            this.bra > this.ket ||
            this.ket > this.limit ||
            this.limit > this.current.length)
        {
            return false;
        }
        return true;
    };

    this.slice_from = function(s)
    {
        var result = false;
	if (this.slice_check())
        {
	    this.replace_s(this.bra, this.ket, s);
            result = true;
        }
        return result;
    };

    this.slice_del = function()
    {
	return this.slice_from("");
    };

    this.insert = function(c_bra, c_ket, s)
    {
        var adjustment = this.replace_s(c_bra, c_ket, s);
	if (c_bra <= this.bra) this.bra += adjustment;
	if (c_bra <= this.ket) this.ket += adjustment;
    };

    this.slice_to = function()
    {
        var result = '';
	if (this.slice_check())
        {
            result = this.current.slice(this.bra, this.ket);
        }
        return result;
    };

    this.assign_to = function()
    {
        return this.current.slice(0, this.limit);
    };
};
<|endoftext|>