<commit_before>/**
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/

/* jshint node:true, bitwise:true, undef:true, trailing:true, quotmark:true,
          indent:4, unused:vars, latedef:nofunc,
          unused:false, expr:true
*/

var platform_modules   = require('./platforms'),
    path               = require('path'),
    config_changes     = require('./util/config-changes'),
    xml_helpers        = require('../util/xml-helpers'),
    wp8                = require('./platforms/wp8'),
    windows            = require('./platforms/windows'),
    common             = require('./platforms/common'),
    fs                 = require('fs'),
    childProcess       = require('child_process'),
    shell              = require('shelljs'),
    util               = require('util'),
    events             = require('../events'),
    plugman            = require('./plugman'),
    et                 = require('elementtree'),
    prepareNamespace   = require('./util/prepare-namespace'),
    bundle             = require('cordova-js/tasks/lib/bundle-browserify'),
    requireTr          = require('cordova-js/tasks/lib/require-tr'),
    writeLicenseHeader = require('cordova-js/tasks/lib/write-license-header'),
    computeCommitId    = require('cordova-js/tasks/lib/compute-commit-id');

function uninstallQueuedPlugins(platform_json, wwwDir) {
    // Check if there are any plugins queued for uninstallation, and if so, remove any of their plugin web assets loaded in
    // via <js-module> elements
    var plugins_to_uninstall = platform_json.prepare_queue.uninstalled;
    if (plugins_to_uninstall && plugins_to_uninstall.length) {
        var plugins_www = path.join(wwwDir, 'plugins');
        if (fs.existsSync(plugins_www)) {
            plugins_to_uninstall.forEach(function(plug) {
                var id = plug.id;
                var plugin_modules = path.join(plugins_www, id);
                if (fs.existsSync(plugin_modules)) {
                    events.emit('verbose', 'Removing plugins directory from www "'+plugin_modules+'"');
                    shell.rm('-rf', plugin_modules);
                }
            });
        }
    }
}

function generateFinalBundle(platform, libraryRelease, outReleaseFile, commitId, platformVersion) {

    var outReleaseFileStream = fs.createWriteStream(outReleaseFile);
    var time = new Date().valueOf();

    writeLicenseHeader(outReleaseFileStream, platform, commitId, platformVersion);

    var releaseBundle = libraryRelease.bundle();

    releaseBundle.pipe(outReleaseFileStream);

    outReleaseFileStream.on('finish', function() {
        var newtime = new Date().valueOf() - time;
        plugman.emit('verbose', 'generated cordova.' + platform + '.js @ ' + commitId + ' in ' + newtime + 'ms');
        // TODO clean up all the *.browserify files
    });

    outReleaseFileStream.on('error', function(err) {
        var newtime = new Date().valueOf() - time;
        console.log('error while generating cordova_b.js');
        plugman.emit('verbose', 'error while generating cordova.js');
    });

}

// Called on --prepare.
// Sets up each plugin's Javascript code to be loaded properly.
// Expects a path to the project (platforms/android in CLI, . in plugman-only),
// a path to where the plugins are downloaded, the www dir, and the platform ('android', 'ios', etc.).
module.exports = function handlePrepare(project_dir, platform, plugins_dir, www_dir, is_top_level) {
    // Process:
    // - Do config munging by calling into config-changes module
    // - List all plugins in plugins_dir
    // - Load and parse their plugin.xml files.
    // - Skip those without support for this platform. (No <platform> tags means JS-only!)
    // - Build a list of all their js-modules, including platform-specific js-modules.
    // - For each js-module (general first, then platform) build up an object storing the path and any clobbers, merges and runs for it.
    events.emit('verbose', 'Preparing ' + platform + ' browserify project');
    var platform_json = config_changes.get_platform_json(plugins_dir, platform);
    var wwwDir = www_dir || platform_modules[platform].www_dir(project_dir);
    var scripts = [];

    uninstallQueuedPlugins(platform_json, www_dir);

    events.emit('verbose', 'Processing configuration changes for plugins.');
    config_changes.process(plugins_dir, project_dir, platform);

    if(!is_top_level) return;

    requireTr.platform = platform;
    var platformVersion;
    //console.log(project_dir);
    computeCommitId(function(commitId) {
        //run version script for each platform to get platformVersion
        var versionPath = path.join(project_dir, '/cordova/version');
        if(!fs.existsSync(versionPath)) {
            //non cli project
            console.log('non cli');
            console.log(project_dir);
            versionPath = path.join(project_dir, '/cordova/version');
            console.log(platform);
        }
        childProcess.exec(versionPath, function(err, stdout, stderr) {
            console.log(versionPath);
            if (err) {
                platformVersion = 'N/A';
                console.log('Error running platform version script');
                console.log(err);
            } else {
                platformVersion = stdout.trim();
                console.log('platformVersion: ' + platformVersion);

                var libraryRelease = bundle(platform, false, commitId, platformVersion);

                platform_json = config_changes.get_platform_json(plugins_dir, platform);
                var plugins = Object.keys(platform_json.installed_plugins).concat(Object.keys(platform_json.dependent_plugins));
                events.emit('verbose', 'Iterating over installed plugins:', plugins);

                plugins && plugins.forEach(function(plugin) {
                    var pluginDir = path.join(plugins_dir, plugin),
                        pluginXML = path.join(pluginDir, 'plugin.xml');
                    if (!fs.existsSync(pluginXML)) {
                        plugman.emit('warn', 'Missing file: ' + pluginXML);
                        return;
                    }
                    var xml = xml_helpers.parseElementtreeSync(pluginXML);

                    var plugin_id = xml.getroot().attrib.id;

                    // add the plugins dir to the platform's www.
                    var platformPluginsDir = path.join(wwwDir, 'plugins');
                    // XXX this should not be here if there are no js-module. It leaves an empty plugins/ directory
                    shell.mkdir('-p', platformPluginsDir);

                    var jsModules = xml.findall('./js-module');
                    var assets = xml.findall('asset');
                    var platformTag = xml.find(util.format('./platform[@name="%s"]', platform));

                    if (platformTag) {
                        assets = assets.concat(platformTag.findall('./asset'));
                        jsModules = jsModules.concat(platformTag.findall('./js-module'));
                    }

                    // Copy www assets described in <asset> tags.
                    assets = assets || [];
                    assets.forEach(function(asset) {
                        common.asset.install(asset, pluginDir, wwwDir);
                    });
                    jsModules.forEach(function(module) {
                        // Copy the plugin's files into the www directory.
                        // NB: We can't always use path.* functions here, because they will use platform slashes.
                        // But the path in the plugin.xml and in the cordova_plugins.js should be always forward slashes.
                        var pathParts = module.attrib.src.split('/');

                        var fsDirname = path.join.apply(path, pathParts.slice(0, -1));
                        var fsDir = path.join(platformPluginsDir, plugin_id, fsDirname);
                        shell.mkdir('-p', fsDir);

                        // Read in the file, prepend the cordova.define, and write it back out.
                        var moduleName = plugin_id + '.';
                        if (module.attrib.name) {
                            moduleName += module.attrib.name;
                        } else {
                            moduleName += path.basename(module.attrib.src, '.js');
                        }

                        var fsPath = path.join.apply(path, pathParts);
                        var scriptPath = path.join(pluginDir, fsPath);

                        requireTr.addModule({symbol: moduleName, path: scriptPath});

                        module.getchildren().forEach(function(child) {
                            if (child.tag.toLowerCase() == 'clobbers') {
                                fs.appendFileSync(scriptPath,
                                  prepareNamespace(child.attrib.target, 'c'),
                                  'utf-8');
                            } else if (child.tag.toLowerCase() == 'merges') {
                                fs.appendFileSync(scriptPath,
                                  prepareNamespace(child.attrib.target, 'm'),
                                  'utf-8');
                            }
                        });
                        scripts.push(scriptPath);
                    });
                });

                libraryRelease.transform(requireTr.transform);

                scripts.forEach(function(script) {
                    libraryRelease.add(script);
                });

                var outReleaseFile = path.join(wwwDir, 'cordova.js');

                generateFinalBundle(platform, libraryRelease, outReleaseFile, commitId, platformVersion);
            }
        });
    });
};
<commit_msg>removed console.logs<commit_after>/**
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/

/* jshint node:true, bitwise:true, undef:true, trailing:true, quotmark:true,
          indent:4, unused:vars, latedef:nofunc,
          unused:false, expr:true
*/

var platform_modules   = require('./platforms'),
    path               = require('path'),
    config_changes     = require('./util/config-changes'),
    xml_helpers        = require('../util/xml-helpers'),
    wp8                = require('./platforms/wp8'),
    windows            = require('./platforms/windows'),
    common             = require('./platforms/common'),
    fs                 = require('fs'),
    childProcess       = require('child_process'),
    shell              = require('shelljs'),
    util               = require('util'),
    events             = require('../events'),
    plugman            = require('./plugman'),
    et                 = require('elementtree'),
    prepareNamespace   = require('./util/prepare-namespace'),
    bundle             = require('cordova-js/tasks/lib/bundle-browserify'),
    requireTr          = require('cordova-js/tasks/lib/require-tr'),
    writeLicenseHeader = require('cordova-js/tasks/lib/write-license-header'),
    computeCommitId    = require('cordova-js/tasks/lib/compute-commit-id');

function uninstallQueuedPlugins(platform_json, wwwDir) {
    // Check if there are any plugins queued for uninstallation, and if so, remove any of their plugin web assets loaded in
    // via <js-module> elements
    var plugins_to_uninstall = platform_json.prepare_queue.uninstalled;
    if (plugins_to_uninstall && plugins_to_uninstall.length) {
        var plugins_www = path.join(wwwDir, 'plugins');
        if (fs.existsSync(plugins_www)) {
            plugins_to_uninstall.forEach(function(plug) {
                var id = plug.id;
                var plugin_modules = path.join(plugins_www, id);
                if (fs.existsSync(plugin_modules)) {
                    events.emit('verbose', 'Removing plugins directory from www "'+plugin_modules+'"');
                    shell.rm('-rf', plugin_modules);
                }
            });
        }
    }
}

function generateFinalBundle(platform, libraryRelease, outReleaseFile, commitId, platformVersion) {

    var outReleaseFileStream = fs.createWriteStream(outReleaseFile);
    var time = new Date().valueOf();

    writeLicenseHeader(outReleaseFileStream, platform, commitId, platformVersion);

    var releaseBundle = libraryRelease.bundle();

    releaseBundle.pipe(outReleaseFileStream);

    outReleaseFileStream.on('finish', function() {
        var newtime = new Date().valueOf() - time;
        plugman.emit('verbose', 'generated cordova.' + platform + '.js @ ' + commitId + ' in ' + newtime + 'ms');
        // TODO clean up all the *.browserify files
    });

    outReleaseFileStream.on('error', function(err) {
        var newtime = new Date().valueOf() - time;
        events.emit('log', 'error while generating cordova.js');
    });

}

// Called on --prepare.
// Sets up each plugin's Javascript code to be loaded properly.
// Expects a path to the project (platforms/android in CLI, . in plugman-only),
// a path to where the plugins are downloaded, the www dir, and the platform ('android', 'ios', etc.).
module.exports = function handlePrepare(project_dir, platform, plugins_dir, www_dir, is_top_level) {
    // Process:
    // - Do config munging by calling into config-changes module
    // - List all plugins in plugins_dir
    // - Load and parse their plugin.xml files.
    // - Skip those without support for this platform. (No <platform> tags means JS-only!)
    // - Build a list of all their js-modules, including platform-specific js-modules.
    // - For each js-module (general first, then platform) build up an object storing the path and any clobbers, merges and runs for it.
    events.emit('verbose', 'Preparing ' + platform + ' browserify project');
    var platform_json = config_changes.get_platform_json(plugins_dir, platform);
    var wwwDir = www_dir || platform_modules[platform].www_dir(project_dir);
    var scripts = [];

    uninstallQueuedPlugins(platform_json, www_dir);

    events.emit('verbose', 'Processing configuration changes for plugins.');
    config_changes.process(plugins_dir, project_dir, platform);

    if(!is_top_level) return;

    requireTr.platform = platform;
    var platformVersion;
    computeCommitId(function(commitId) {
        //run version script for each platform to get platformVersion
        var versionPath = path.join(project_dir, '/cordova/version');
        childProcess.exec(versionPath, function(err, stdout, stderr) {
            if (err) {
                platformVersion = 'N/A';
                events.emit('log', 'Error running platform version script');
                events.emit('log', err);
            } else {
                platformVersion = stdout.trim();

                var libraryRelease = bundle(platform, false, commitId, platformVersion);

                platform_json = config_changes.get_platform_json(plugins_dir, platform);
                var plugins = Object.keys(platform_json.installed_plugins).concat(Object.keys(platform_json.dependent_plugins));
                events.emit('verbose', 'Iterating over installed plugins:', plugins);

                plugins && plugins.forEach(function(plugin) {
                    var pluginDir = path.join(plugins_dir, plugin),
                        pluginXML = path.join(pluginDir, 'plugin.xml');
                    if (!fs.existsSync(pluginXML)) {
                        plugman.emit('warn', 'Missing file: ' + pluginXML);
                        return;
                    }
                    var xml = xml_helpers.parseElementtreeSync(pluginXML);

                    var plugin_id = xml.getroot().attrib.id;

                    // add the plugins dir to the platform's www.
                    var platformPluginsDir = path.join(wwwDir, 'plugins');
                    // XXX this should not be here if there are no js-module. It leaves an empty plugins/ directory
                    shell.mkdir('-p', platformPluginsDir);

                    var jsModules = xml.findall('./js-module');
                    var assets = xml.findall('asset');
                    var platformTag = xml.find(util.format('./platform[@name="%s"]', platform));

                    if (platformTag) {
                        assets = assets.concat(platformTag.findall('./asset'));
                        jsModules = jsModules.concat(platformTag.findall('./js-module'));
                    }

                    // Copy www assets described in <asset> tags.
                    assets = assets || [];
                    assets.forEach(function(asset) {
                        common.asset.install(asset, pluginDir, wwwDir);
                    });
                    jsModules.forEach(function(module) {
                        // Copy the plugin's files into the www directory.
                        // NB: We can't always use path.* functions here, because they will use platform slashes.
                        // But the path in the plugin.xml and in the cordova_plugins.js should be always forward slashes.
                        var pathParts = module.attrib.src.split('/');

                        var fsDirname = path.join.apply(path, pathParts.slice(0, -1));
                        var fsDir = path.join(platformPluginsDir, plugin_id, fsDirname);
                        shell.mkdir('-p', fsDir);

                        // Read in the file, prepend the cordova.define, and write it back out.
                        var moduleName = plugin_id + '.';
                        if (module.attrib.name) {
                            moduleName += module.attrib.name;
                        } else {
                            moduleName += path.basename(module.attrib.src, '.js');
                        }

                        var fsPath = path.join.apply(path, pathParts);
                        var scriptPath = path.join(pluginDir, fsPath);

                        requireTr.addModule({symbol: moduleName, path: scriptPath});

                        module.getchildren().forEach(function(child) {
                            if (child.tag.toLowerCase() == 'clobbers') {
                                fs.appendFileSync(scriptPath,
                                  prepareNamespace(child.attrib.target, 'c'),
                                  'utf-8');
                            } else if (child.tag.toLowerCase() == 'merges') {
                                fs.appendFileSync(scriptPath,
                                  prepareNamespace(child.attrib.target, 'm'),
                                  'utf-8');
                            }
                        });
                        scripts.push(scriptPath);
                    });
                });

                libraryRelease.transform(requireTr.transform);

                scripts.forEach(function(script) {
                    libraryRelease.add(script);
                });

                var outReleaseFile = path.join(wwwDir, 'cordova.js');

                generateFinalBundle(platform, libraryRelease, outReleaseFile, commitId, platformVersion);
            }
        });
    });
};
<|endoftext|>


<commit_before>/* global moment */
import {parseDateString, formatDate} from 'ghost/utils/date-formatting';
import SettingsMenuMixin from 'ghost/mixins/settings-menu-controller';
import SlugGenerator from 'ghost/models/slug-generator';
import boundOneWay from 'ghost/utils/bound-one-way';
import isNumber from 'ghost/utils/isNumber';

var PostSettingsMenuController = Ember.Controller.extend(SettingsMenuMixin, {
    debounceId: null,
    lastPromise: null,
    selectedAuthor: null,
    uploaderReference: null,

    initializeSelectedAuthor: function () {
        var self = this;

        return this.get('model.author').then(function (author) {
            self.set('selectedAuthor', author);
            return author;
        });
    }.observes('model'),

    changeAuthor: function () {
        var author = this.get('model.author'),
            selectedAuthor = this.get('selectedAuthor'),
            model = this.get('model'),
            self = this;

        // return if nothing changed
        if (selectedAuthor.get('id') === author.get('id')) {
            return;
        }

        model.set('author', selectedAuthor);

        // if this is a new post (never been saved before), don't try to save it
        if (this.get('model.isNew')) {
            return;
        }

        model.save().catch(function (errors) {
            self.showErrors(errors);
            self.set('selectedAuthor', author);
            model.rollback();
        });
    }.observes('selectedAuthor'),

    authors: Ember.computed(function () {
        // Loaded asynchronously, so must use promise proxies.
        var deferred = {};

        deferred.promise = this.store.find('user', {limit: 'all'}).then(function (users) {
            return users.rejectBy('id', 'me').sortBy('name');
        }).then(function (users) {
            return users.filter(function (user) {
                return user.get('active');
            });
        });

        return Ember.ArrayProxy
            .extend(Ember.PromiseProxyMixin)
            .create(deferred);
    }),

    /*jshint unused:false */
    publishedAtValue: Ember.computed('model.published_at', function (key, value) {
        var pubDate = this.get('model.published_at');

        // We're using a fake setter to reset
        // the cache for this property
        if (arguments.length > 1) {
            return formatDate(moment());
        }

        if (pubDate) {
            return formatDate(pubDate);
        }

        return formatDate(moment());
    }),
    /*jshint unused:true */

    slugValue: boundOneWay('model.slug'),

    // Lazy load the slug generator
    slugGenerator: Ember.computed(function () {
        return SlugGenerator.create({
            ghostPaths: this.get('ghostPaths'),
            slugType: 'post'
        });
    }),

    // Requests slug from title
    generateAndSetSlug: function (destination) {
        var self = this,
            title = this.get('model.titleScratch'),
            afterSave = this.get('lastPromise'),
            promise;

        // Only set an "untitled" slug once per post
        if (title === '(Untitled)' && this.get('model.slug')) {
            return;
        }

        promise = Ember.RSVP.resolve(afterSave).then(function () {
            return self.get('slugGenerator').generateSlug(title).then(function (slug) {
                self.set(destination, slug);
            }).catch(function () {
                // Nothing to do (would be nice to log this somewhere though),
                // but a rejected promise needs to be handled here so that a resolved
                // promise is returned.
            });
        });

        this.set('lastPromise', promise);
    },

    metaTitleScratch: boundOneWay('model.meta_title'),
    metaDescriptionScratch: boundOneWay('model.meta_description'),

    seoTitle: Ember.computed('model.titleScratch', 'metaTitleScratch', function () {
        var metaTitle = this.get('metaTitleScratch') || '';

        metaTitle = metaTitle.length > 0 ? metaTitle : this.get('model.titleScratch');

        if (metaTitle.length > 70) {
            metaTitle = metaTitle.substring(0, 70).trim();
            metaTitle = Ember.Handlebars.Utils.escapeExpression(metaTitle);
            metaTitle = new Ember.Handlebars.SafeString(metaTitle + '…');
        }

        return metaTitle;
    }),

    seoDescription: Ember.computed('model.scratch', 'metaDescriptionScratch', function () {
        var metaDescription = this.get('metaDescriptionScratch') || '',
            el,
            html = '',
            placeholder;

        if (metaDescription.length > 0) {
            placeholder = metaDescription;
        } else {
            el = $('.rendered-markdown');

            // Get rendered markdown
            if (el !== undefined && el.length > 0) {
                html = el.clone();
                html.find('.js-drop-zone').remove();
                html = html[0].innerHTML;
            }

            // Strip HTML
            placeholder = $('<div />', {html: html}).text();
            // Replace new lines and trim
            // jscs: disable
            placeholder = placeholder.replace(/\n+/g, ' ').trim();
            // jscs: enable
        }

        if (placeholder.length > 156) {
            // Limit to 156 characters
            placeholder = placeholder.substring(0, 156).trim();
            placeholder = Ember.Handlebars.Utils.escapeExpression(placeholder);
            placeholder = new Ember.Handlebars.SafeString(placeholder + '…');
        }

        return placeholder;
    }),

    seoURL: Ember.computed('model.slug', function () {
        var blogUrl = this.get('config').blogUrl,
            seoSlug = this.get('model.slug') ? this.get('model.slug') : '',
            seoURL = blogUrl + '/' + seoSlug;

        // only append a slash to the URL if the slug exists
        if (seoSlug) {
            seoURL += '/';
        }

        if (seoURL.length > 70) {
            seoURL = seoURL.substring(0, 70).trim();
            seoURL = new Ember.Handlebars.SafeString(seoURL + '…');
        }

        return seoURL;
    }),

    // observe titleScratch, keeping the post's slug in sync
    // with it until saved for the first time.
    addTitleObserver: function () {
        if (this.get('model.isNew') || this.get('model.title') === '(Untitled)') {
            this.addObserver('model.titleScratch', this, 'titleObserver');
        }
    }.observes('model'),

    titleObserver: function () {
        var debounceId,
            title = this.get('model.title');

        // generate a slug if a post is new and doesn't have a title yet or
        // if the title is still '(Untitled)' and the slug is unaltered.
        if ((this.get('model.isNew') && !title) || title === '(Untitled)') {
            debounceId = Ember.run.debounce(this, 'generateAndSetSlug', ['slug'], 700);
        }

        this.set('debounceId', debounceId);
    },

    showErrors: function (errors) {
        errors = Ember.isArray(errors) ? errors : [errors];
        this.notifications.showErrors(errors);
    },

    showSuccess: function (message) {
        this.notifications.showSuccess(message);
    },

    actions: {
        togglePage: function () {
            var self = this;

            this.toggleProperty('model.page');
            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        toggleFeatured: function () {
            var self = this;

            this.toggleProperty('model.featured');

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save(this.get('saveOptions')).catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        /**
         * triggered by user manually changing slug
         */
        updateSlug: function (newSlug) {
            var slug = this.get('model.slug'),
                self = this;

            newSlug = newSlug || slug;

            newSlug = newSlug && newSlug.trim();

            // Ignore unchanged slugs or candidate slugs that are empty
            if (!newSlug || slug === newSlug) {
                // reset the input to its previous state
                this.set('slugValue', slug);

                return;
            }

            this.get('slugGenerator').generateSlug(newSlug).then(function (serverSlug) {
                // If after getting the sanitized and unique slug back from the API
                // we end up with a slug that matches the existing slug, abort the change
                if (serverSlug === slug) {
                    return;
                }

                // Because the server transforms the candidate slug by stripping
                // certain characters and appending a number onto the end of slugs
                // to enforce uniqueness, there are cases where we can get back a
                // candidate slug that is a duplicate of the original except for
                // the trailing incrementor (e.g., this-is-a-slug and this-is-a-slug-2)

                // get the last token out of the slug candidate and see if it's a number
                var slugTokens = serverSlug.split('-'),
                    check = Number(slugTokens.pop());

                // if the candidate slug is the same as the existing slug except
                // for the incrementor then the existing slug should be used
                if (isNumber(check) && check > 0) {
                    if (slug === slugTokens.join('-') && serverSlug !== newSlug) {
                        self.set('slugValue', slug);

                        return;
                    }
                }

                self.set('model.slug', serverSlug);

                if (self.hasObserverFor('model.titleScratch')) {
                    self.removeObserver('model.titleScratch', self, 'titleObserver');
                }

                // If this is a new post.  Don't save the model.  Defer the save
                // to the user pressing the save button
                if (self.get('model.isNew')) {
                    return;
                }

                return self.get('model').save();
            }).catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        /**
         * Parse user's set published date.
         * Action sent by post settings menu view.
         * (#1351)
         */
        setPublishedAt: function (userInput) {
            var errMessage = '',
                newPublishedAt = parseDateString(userInput),
                publishedAt = this.get('model.published_at'),
                self = this;

            if (!userInput) {
                // Clear out the published_at field for a draft
                if (this.get('model.isDraft')) {
                    this.set('model.published_at', null);
                }

                return;
            }

            // Validate new Published date
            if (!newPublishedAt.isValid()) {
                errMessage = 'Published Date must be a valid date with format: ' +
                    'DD MMM YY @ HH:mm (e.g. 6 Dec 14 @ 15:00)';
            }
            if (newPublishedAt.diff(new Date(), 'h') > 0) {
                errMessage = 'Published Date cannot currently be in the future.';
            }

            // If errors, notify and exit.
            if (errMessage) {
                this.showErrors(errMessage);

                return;
            }

            // Do nothing if the user didn't actually change the date
            if (publishedAt && publishedAt.isSame(newPublishedAt)) {
                return;
            }

            // Validation complete
            this.set('model.published_at', newPublishedAt);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        setMetaTitle: function (metaTitle) {
            var self = this,
                currentTitle = this.get('model.meta_title') || '';

            // Only update if the title has changed
            if (currentTitle === metaTitle) {
                return;
            }

            this.set('model.meta_title', metaTitle);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
            });
        },

        setMetaDescription: function (metaDescription) {
            var self = this,
                currentDescription = this.get('model.meta_description') || '';

            // Only update if the description has changed
            if (currentDescription === metaDescription) {
                return;
            }

            this.set('model.meta_description', metaDescription);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
            });
        },

        setCoverImage: function (image) {
            var self = this;

            this.set('model.image', image);

            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        clearCoverImage: function () {
            var self = this;

            this.set('model.image', '');

            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        resetUploader: function () {
            var uploader = this.get('uploaderReference');

            if (uploader && uploader[0]) {
                uploader[0].uploaderUi.reset();
            }
        },

        resetPubDate: function () {
            this.set('publishedAtValue', '');
        }
    }
});

export default PostSettingsMenuController;
<commit_msg>Fix regression in re-setting slug on untitled post<commit_after>/* global moment */
import {parseDateString, formatDate} from 'ghost/utils/date-formatting';
import SettingsMenuMixin from 'ghost/mixins/settings-menu-controller';
import SlugGenerator from 'ghost/models/slug-generator';
import boundOneWay from 'ghost/utils/bound-one-way';
import isNumber from 'ghost/utils/isNumber';

var PostSettingsMenuController = Ember.Controller.extend(SettingsMenuMixin, {
    debounceId: null,
    lastPromise: null,
    selectedAuthor: null,
    uploaderReference: null,

    initializeSelectedAuthor: function () {
        var self = this;

        return this.get('model.author').then(function (author) {
            self.set('selectedAuthor', author);
            return author;
        });
    }.observes('model'),

    changeAuthor: function () {
        var author = this.get('model.author'),
            selectedAuthor = this.get('selectedAuthor'),
            model = this.get('model'),
            self = this;

        // return if nothing changed
        if (selectedAuthor.get('id') === author.get('id')) {
            return;
        }

        model.set('author', selectedAuthor);

        // if this is a new post (never been saved before), don't try to save it
        if (this.get('model.isNew')) {
            return;
        }

        model.save().catch(function (errors) {
            self.showErrors(errors);
            self.set('selectedAuthor', author);
            model.rollback();
        });
    }.observes('selectedAuthor'),

    authors: Ember.computed(function () {
        // Loaded asynchronously, so must use promise proxies.
        var deferred = {};

        deferred.promise = this.store.find('user', {limit: 'all'}).then(function (users) {
            return users.rejectBy('id', 'me').sortBy('name');
        }).then(function (users) {
            return users.filter(function (user) {
                return user.get('active');
            });
        });

        return Ember.ArrayProxy
            .extend(Ember.PromiseProxyMixin)
            .create(deferred);
    }),

    /*jshint unused:false */
    publishedAtValue: Ember.computed('model.published_at', function (key, value) {
        var pubDate = this.get('model.published_at');

        // We're using a fake setter to reset
        // the cache for this property
        if (arguments.length > 1) {
            return formatDate(moment());
        }

        if (pubDate) {
            return formatDate(pubDate);
        }

        return formatDate(moment());
    }),
    /*jshint unused:true */

    slugValue: boundOneWay('model.slug'),

    // Lazy load the slug generator
    slugGenerator: Ember.computed(function () {
        return SlugGenerator.create({
            ghostPaths: this.get('ghostPaths'),
            slugType: 'post'
        });
    }),

    // Requests slug from title
    generateAndSetSlug: function (destination) {
        var self = this,
            title = this.get('model.titleScratch'),
            afterSave = this.get('lastPromise'),
            promise;

        // Only set an "untitled" slug once per post
        if (title === '(Untitled)' && this.get('model.slug')) {
            return;
        }

        promise = Ember.RSVP.resolve(afterSave).then(function () {
            return self.get('slugGenerator').generateSlug(title).then(function (slug) {
                self.set(destination, slug);
            }).catch(function () {
                // Nothing to do (would be nice to log this somewhere though),
                // but a rejected promise needs to be handled here so that a resolved
                // promise is returned.
            });
        });

        this.set('lastPromise', promise);
    },

    metaTitleScratch: boundOneWay('model.meta_title'),
    metaDescriptionScratch: boundOneWay('model.meta_description'),

    seoTitle: Ember.computed('model.titleScratch', 'metaTitleScratch', function () {
        var metaTitle = this.get('metaTitleScratch') || '';

        metaTitle = metaTitle.length > 0 ? metaTitle : this.get('model.titleScratch');

        if (metaTitle.length > 70) {
            metaTitle = metaTitle.substring(0, 70).trim();
            metaTitle = Ember.Handlebars.Utils.escapeExpression(metaTitle);
            metaTitle = new Ember.Handlebars.SafeString(metaTitle + '…');
        }

        return metaTitle;
    }),

    seoDescription: Ember.computed('model.scratch', 'metaDescriptionScratch', function () {
        var metaDescription = this.get('metaDescriptionScratch') || '',
            el,
            html = '',
            placeholder;

        if (metaDescription.length > 0) {
            placeholder = metaDescription;
        } else {
            el = $('.rendered-markdown');

            // Get rendered markdown
            if (el !== undefined && el.length > 0) {
                html = el.clone();
                html.find('.js-drop-zone').remove();
                html = html[0].innerHTML;
            }

            // Strip HTML
            placeholder = $('<div />', {html: html}).text();
            // Replace new lines and trim
            // jscs: disable
            placeholder = placeholder.replace(/\n+/g, ' ').trim();
            // jscs: enable
        }

        if (placeholder.length > 156) {
            // Limit to 156 characters
            placeholder = placeholder.substring(0, 156).trim();
            placeholder = Ember.Handlebars.Utils.escapeExpression(placeholder);
            placeholder = new Ember.Handlebars.SafeString(placeholder + '…');
        }

        return placeholder;
    }),

    seoURL: Ember.computed('model.slug', function () {
        var blogUrl = this.get('config').blogUrl,
            seoSlug = this.get('model.slug') ? this.get('model.slug') : '',
            seoURL = blogUrl + '/' + seoSlug;

        // only append a slash to the URL if the slug exists
        if (seoSlug) {
            seoURL += '/';
        }

        if (seoURL.length > 70) {
            seoURL = seoURL.substring(0, 70).trim();
            seoURL = new Ember.Handlebars.SafeString(seoURL + '…');
        }

        return seoURL;
    }),

    // observe titleScratch, keeping the post's slug in sync
    // with it until saved for the first time.
    addTitleObserver: function () {
        if (this.get('model.isNew') || this.get('model.title') === '(Untitled)') {
            this.addObserver('model.titleScratch', this, 'titleObserver');
        }
    }.observes('model'),

    titleObserver: function () {
        var debounceId,
            title = this.get('model.title');

        // generate a slug if a post is new and doesn't have a title yet or
        // if the title is still '(Untitled)' and the slug is unaltered.
        if ((this.get('model.isNew') && !title) || title === '(Untitled)') {
            debounceId = Ember.run.debounce(this, 'generateAndSetSlug', 'model.slug', 700);
        }

        this.set('debounceId', debounceId);
    },

    showErrors: function (errors) {
        errors = Ember.isArray(errors) ? errors : [errors];
        this.notifications.showErrors(errors);
    },

    showSuccess: function (message) {
        this.notifications.showSuccess(message);
    },

    actions: {
        togglePage: function () {
            var self = this;

            this.toggleProperty('model.page');
            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        toggleFeatured: function () {
            var self = this;

            this.toggleProperty('model.featured');

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save(this.get('saveOptions')).catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        /**
         * triggered by user manually changing slug
         */
        updateSlug: function (newSlug) {
            var slug = this.get('model.slug'),
                self = this;

            newSlug = newSlug || slug;

            newSlug = newSlug && newSlug.trim();

            // Ignore unchanged slugs or candidate slugs that are empty
            if (!newSlug || slug === newSlug) {
                // reset the input to its previous state
                this.set('slugValue', slug);

                return;
            }

            this.get('slugGenerator').generateSlug(newSlug).then(function (serverSlug) {
                // If after getting the sanitized and unique slug back from the API
                // we end up with a slug that matches the existing slug, abort the change
                if (serverSlug === slug) {
                    return;
                }

                // Because the server transforms the candidate slug by stripping
                // certain characters and appending a number onto the end of slugs
                // to enforce uniqueness, there are cases where we can get back a
                // candidate slug that is a duplicate of the original except for
                // the trailing incrementor (e.g., this-is-a-slug and this-is-a-slug-2)

                // get the last token out of the slug candidate and see if it's a number
                var slugTokens = serverSlug.split('-'),
                    check = Number(slugTokens.pop());

                // if the candidate slug is the same as the existing slug except
                // for the incrementor then the existing slug should be used
                if (isNumber(check) && check > 0) {
                    if (slug === slugTokens.join('-') && serverSlug !== newSlug) {
                        self.set('slugValue', slug);

                        return;
                    }
                }

                self.set('model.slug', serverSlug);

                if (self.hasObserverFor('model.titleScratch')) {
                    self.removeObserver('model.titleScratch', self, 'titleObserver');
                }

                // If this is a new post.  Don't save the model.  Defer the save
                // to the user pressing the save button
                if (self.get('model.isNew')) {
                    return;
                }

                return self.get('model').save();
            }).catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        /**
         * Parse user's set published date.
         * Action sent by post settings menu view.
         * (#1351)
         */
        setPublishedAt: function (userInput) {
            var errMessage = '',
                newPublishedAt = parseDateString(userInput),
                publishedAt = this.get('model.published_at'),
                self = this;

            if (!userInput) {
                // Clear out the published_at field for a draft
                if (this.get('model.isDraft')) {
                    this.set('model.published_at', null);
                }

                return;
            }

            // Validate new Published date
            if (!newPublishedAt.isValid()) {
                errMessage = 'Published Date must be a valid date with format: ' +
                    'DD MMM YY @ HH:mm (e.g. 6 Dec 14 @ 15:00)';
            }
            if (newPublishedAt.diff(new Date(), 'h') > 0) {
                errMessage = 'Published Date cannot currently be in the future.';
            }

            // If errors, notify and exit.
            if (errMessage) {
                this.showErrors(errMessage);

                return;
            }

            // Do nothing if the user didn't actually change the date
            if (publishedAt && publishedAt.isSame(newPublishedAt)) {
                return;
            }

            // Validation complete
            this.set('model.published_at', newPublishedAt);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        setMetaTitle: function (metaTitle) {
            var self = this,
                currentTitle = this.get('model.meta_title') || '';

            // Only update if the title has changed
            if (currentTitle === metaTitle) {
                return;
            }

            this.set('model.meta_title', metaTitle);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
            });
        },

        setMetaDescription: function (metaDescription) {
            var self = this,
                currentDescription = this.get('model.meta_description') || '';

            // Only update if the description has changed
            if (currentDescription === metaDescription) {
                return;
            }

            this.set('model.meta_description', metaDescription);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
            });
        },

        setCoverImage: function (image) {
            var self = this;

            this.set('model.image', image);

            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        clearCoverImage: function () {
            var self = this;

            this.set('model.image', '');

            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch(function (errors) {
                self.showErrors(errors);
                self.get('model').rollback();
            });
        },

        resetUploader: function () {
            var uploader = this.get('uploaderReference');

            if (uploader && uploader[0]) {
                uploader[0].uploaderUi.reset();
            }
        },

        resetPubDate: function () {
            this.set('publishedAtValue', '');
        }
    }
});

export default PostSettingsMenuController;
<|endoftext|>


<commit_before>import { mapGetters } from 'vuex'
import VueOfflineMixin from 'vue-offline/mixin'

// Core dependecies
import { productsInCart, closeMicrocart, isMicrocartOpen, removeFromCart, applyCoupon, removeCoupon, appliedCoupon } from '@vue-storefront/core/modules/cart/features'

import onEscapePress from '@vue-storefront/core/mixins/onEscapePress'

export default {
  name: 'Microcart',
  mixins: [
    onEscapePress,
    productsInCart,
    isMicrocartOpen,
    closeMicrocart,
    removeFromCart,
    applyCoupon,
    removeCoupon,
    appliedCoupon,
    VueOfflineMixin
  ],
  props: {
    product: {
      type: Object,
      required: false,
      default: () => { }
    },
    isCheckoutMode: {
      type: Boolean,
      required: false,
      default: () => false
    }
  },
  computed: {
    ...mapGetters({
      totals: 'cart/totals'
    }),
    shipping () {
      return this.$store.state.cart.shipping
    },
    payment () {
      return this.$store.state.cart.payment
    }
  }
}
<commit_msg>[#1433] Removed unused props<commit_after>import { mapGetters } from 'vuex'
import VueOfflineMixin from 'vue-offline/mixin'

// Core dependecies
import { productsInCart, closeMicrocart, isMicrocartOpen, removeFromCart, applyCoupon, removeCoupon, appliedCoupon } from '@vue-storefront/core/modules/cart/features'

import onEscapePress from '@vue-storefront/core/mixins/onEscapePress'

export default {
  name: 'Microcart',
  mixins: [
    onEscapePress,
    productsInCart,
    isMicrocartOpen,
    closeMicrocart,
    removeFromCart,
    applyCoupon,
    removeCoupon,
    appliedCoupon,
    VueOfflineMixin
  ],
  props: {
    isCheckoutMode: {
      type: Boolean,
      required: false,
      default: () => false
    }
  },
  computed: {
    ...mapGetters({
      totals: 'cart/totals'
    }),
    shipping () {
      return this.$store.state.cart.shipping
    },
    payment () {
      return this.$store.state.cart.payment
    }
  }
}
<|endoftext|>


<commit_before>// this file is automatically generated using scripts/updatePackageVersions.js
export default {
  "addon-active": "1.0.0-beta.4",
  "addon-ancestors": "1.0.0-beta.4",
  "addon-prefetch": "1.0.0-beta.4",
  "core": "1.0.0-beta.10",
  "react": "1.0.0-beta.8",
  "redux": "1.0.0-alpha.1",
  "side-effect-scroll": "1.0.0-beta.5",
  "side-effect-title": "1.0.0-beta.5",
  "svelte": "1.0.0-alpha.4",
  "vue": "1.0.0-beta.6"
};
<commit_msg>(docs) Bump react/vue versions [ci skip]<commit_after>// this file is automatically generated using scripts/updatePackageVersions.js
export default {
  "addon-active": "1.0.0-beta.4",
  "addon-ancestors": "1.0.0-beta.4",
  "addon-prefetch": "1.0.0-beta.4",
  "core": "1.0.0-beta.10",
  "react": "1.0.0-beta.9",
  "redux": "1.0.0-alpha.1",
  "side-effect-scroll": "1.0.0-beta.5",
  "side-effect-title": "1.0.0-beta.5",
  "svelte": "1.0.0-alpha.4",
  "vue": "1.0.0-beta.7"
};
<|endoftext|>


<commit_before>(function () {
    'use strict';

    var module = angular.module('TextCoder.controllers', [
        'TextCoder.services',
        'angularSpinner',
        'angucomplete-alt',
        'smart-table'
    ]);

    module.config(['$interpolateProvider', function ($interpolateProvider) {
        $interpolateProvider.startSymbol('{$');
        $interpolateProvider.endSymbol('$}');
    }]);

    module.config(['usSpinnerConfigProvider', function (usSpinnerConfigProvider) {
        usSpinnerConfigProvider.setDefaults({
            color: '#111'
        });
    }]);

    var DictionaryController = function ($scope, Dictionary) {
        $scope.Dictionary = Dictionary;

    };
    DictionaryController.$inject = [
        '$scope',
        'TextCoder.services.Dictionary'
    ];
    module.controller('TextCoder.controllers.DictionaryController', DictionaryController);

    var ViewController = function ($scope, Dictionary, SVMResult, FeatureVector, UserFeatures, usSpinnerService) {

        $scope.spinnerOptions = {
            radius: 20,
            width: 6,
            length: 10,
            color: "#000000"
        };
        var dist_max_height = 20; // in pixel

        $scope.svm_results = undefined;
        $scope.vector = undefined;
        $scope.features = [];

        $scope.load = function(){
            var request = SVMResult.load(Dictionary.id);
            if (request) {
                usSpinnerService.spin('table-spinner');
                request.then(function() {
                    usSpinnerService.stop('table-spinner');
                    SVMResult.dist_scale.range([0, dist_max_height]);
                    $scope.svm_results = SVMResult.data;
                });
            }

        };

        // load the svm results
        $scope.load();

        $scope.style = function(code){
            var colors = ["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"];
            var css = {
                'background-color' : 'none',
                'color': 'black'
            };
            var code_order = (Math.floor(code.order / 2));
            if (code_order  < colors.length ){
                css['background-color'] = colors[colors.length - code_order  - 1];
                if ( code_order  < 3)
                    css['color'] = '#ccc';
            }
            return css;
        };
        $scope.dist = function(code){
            var css = {
                'background-color': 'steelblue',
                'width' : 15,
                'height': SVMResult.dist_scale(code.train_count)
            };
            return css;
        };
        $scope.on_off = function(count){
            var css = {
                'background-color' : 'none',
                'color': 'black'
            };
            if (count > 0){
                css['background-color'] = "#fee0d2";
                //css['color'] = '#ccc';
            }
            return css;
        };
        $scope.active = function(tid){
            return ($scope.vector && $scope.vector.message.id == tid) ? "active" : "";
        };

        $scope.load_vector = function(tid){
            var request = FeatureVector.load(tid);
            if (request) {
                usSpinnerService.spin('vector-spinner');
                request.then(function() {
                    usSpinnerService.stop('vector-spinner');
                    $scope.vector = FeatureVector.data;

                    // TODO (jinasuh): Replace with actual data from service
                    var text = "RT @iNialls_Girl: R.I.P. to the 8 year old boy who died in Bostons explosions, while running for the Sandy Hook kids. #PrayForBoston ht ...";
                    var characters = text.split("");

                    var tokens = ["rt",
                                "@inialls_girl",
                                ":",
                                "r.i.p.",
                                "to",
                                "the",
                                "8",
                                "year",
                                "old",
                                "boy",
                                "who",
                                "died",
                                "in",
                                "bostons",
                                "explosions",
                                ",",
                                "while",
                                "running",
                                "for",
                                "the",
                                "sandy",
                                "hook",
                                "kids",
                                ".",
                                "#prayforboston",
                                "ht",
                                "..."];

                    var tokenItems = [];
                    var charToToken = [];

                    var lowerText = text.toLowerCase();
                    var currentIndex = 0;
                    for (var i = 0; i < tokens.length; i++)
                    {
                        var token = tokens[i];
                        if (token != null && token.length > 0)
                        {
                            var foundIndex = lowerText.substr(currentIndex).indexOf(token) + currentIndex;

                            var tokenItem = {
                                text: token,
                                index: i
                            };

                            currentIndex = foundIndex;
                            tokenItem.startIndex = currentIndex;
                            currentIndex += token.length - 1;
                            tokenItem.endIndex = currentIndex;

                            tokenItems.push(tokenItem);

                            for (var j = tokenItem.startIndex; j <= tokenItem.endIndex; j++)
                            {
                                charToToken[j] = i;
                            }
                        }
                    }

                    $scope.vector.message.text = text;
                    $scope.vector.message.tokens = tokenItems;
                    $scope.vector.message.characters = characters;
                    $scope.vector.message.charToToken = charToToken;
                });
            }
        };

        $scope.getter = {
            'vector': function(feature){
                return $scope.vector.feature_vector[feature.word_index];
            }
        };

        // Feature selection logic and states
        $scope.selectedCharStart = -1;
        $scope.selectedCharEnd = -1;
        $scope.hoveredCharStart = -1;
        $scope.hoveredCharEnd = -1;
        $scope.clickStartTokenItem = undefined;
        $scope.selectedTokens = undefined;
        $scope.selectedTokenIndices = new Map();

        $scope.featureList = {};

        var updateSelection = function(startIndex, endIndex, isSelected, shouldClear) {
            if (shouldClear) {
                $scope.selectedTokenIndices.clear();
            }

            for (var i = startIndex; i <= endIndex; i++) {
                var existing = $scope.selectedTokenIndices.get(i);
                if (existing == i && !isSelected) {
                    $scope.selectedTokenIndices.delete(i);
                }
                else if (existing != i && isSelected) {
                    $scope.selectedTokenIndices.set(i, i);
                }
            }

            // TODO: if the previous or next token is selected, also update the selection for the character (space) in between.
            //console.log($scope.selectedTokenIndices.values());
        };

        $scope.onCharMouseEnter = function(charIndex){
            //console.log("onCharMouseEnter:" + charIndex);

            if ($scope.vector && $scope.vector.message){
                var tokenIndex = $scope.vector.message.charToToken[charIndex];

                if (tokenIndex != undefined && $scope.vector.message.tokens[tokenIndex] != undefined) {
                    var tokenItem = $scope.vector.message.tokens[tokenIndex];
                    $scope.hoveredCharStart = tokenItem.startIndex;
                    $scope.hoveredCharEnd = tokenItem.endIndex;

                    // If we're in the middle of selection, update selected char indices
                    if ($scope.clickStartTokenItem != undefined){
                        if (tokenIndex < $scope.clickStartTokenItem.index){
                            updateSelection(tokenIndex, $scope.clickStartTokenItem.index, true, true);
                        }
                        else if (tokenIndex > $scope.clickStartTokenItem.index){
                            updateSelection($scope.clickStartTokenItem.index, tokenIndex, true, true);
                        }
                    }
                }
                else {
                    $scope.hoveredCharStart = -1;
                    $scope.hoveredCharEnd = -1;
                }
            }
        };

        $scope.onCharMouseLeave = function(charIndex){
            //console.log("onCharMouseLeave:" + charIndex);

            $scope.hoveredCharStart = -1;
            $scope.hoveredCharEnd = -1;
        };

        $scope.onCharMouseDown = function(charIndex, event){
            //console.log("onCharMouseDown:" + charIndex);

            if ($scope.vector && $scope.vector.message) {

                var tokenIndex = $scope.vector.message.charToToken[charIndex];

                if (tokenIndex != undefined && $scope.vector.message.tokens[tokenIndex] != undefined) {

                    var tokenItem = $scope.vector.message.tokens[tokenIndex];

                    var ctrlClick = event.ctrlKey || (event.metaKey && !event.ctrlKey);
                    // if there was a selection at this tokenIndex and mouse was clicked with command/ctrl button,
                    // clear the selection on this token index
                    if ($scope.selectedTokenIndices.get(tokenIndex) == tokenIndex && ctrlClick) {
                        $scope.clickStartTokenItem = undefined;
                        updateSelection(tokenIndex, tokenIndex, false, false);
                    }
                    else {
                        $scope.clickStartTokenItem = tokenItem;
                        updateSelection(tokenIndex, tokenIndex, true, !ctrlClick);
                    }
                }
                else {
                    $scope.clickStartTokenItem = undefined;
                    $scope.selectedTokenIndices.clear();
                }
            }
        };

        $scope.onCharMouseUp = function(charIndex) {
            $scope.clickStartTokenItem = undefined;
            $scope.selectedTokens = undefined;

            if ($scope.selectedTokenIndices.size > 0) {
                if ($scope.vector && $scope.vector.message) {

                    // Get sorted list of selected token indices
                    var indices = [];
                    $scope.selectedTokenIndices.forEach(function (val) {
                        indices.push(val);
                    });
                    indices.sort(function (a, b) {
                        return a - b;
                    });

                    var tokens = [];
                    var currentTokenIndex = -1;
                    for (var i = 0; i < indices.length; i++) {
                        var tokenIndex = indices[i];

                        if (tokenIndex != currentTokenIndex) {
                            tokens.push($scope.vector.message.tokens[tokenIndex].text);
                            currentTokenIndex = tokenIndex;
                        }
                    }

                    $scope.selectedTokens = tokens;
                }
            }
        };

        $scope.charStyle = function(charIndex){
            var style = {};
            if (charIndex >= $scope.hoveredCharStart && charIndex <= $scope.hoveredCharEnd){
                style["background"] = "#ffcc99";
            }

            if ($scope.vector && $scope.vector.message) {
                var tokenIndex = $scope.vector.message.charToToken[charIndex];
                if (tokenIndex != undefined && $scope.selectedTokenIndices.get(tokenIndex) == tokenIndex) {
                    style["background"] = "#ff6600";
                }
            }
            return style;
        };

        $scope.addFeature = function(tokens){
            if (tokens && tokens.length > 0){

                var key = tokens.join(" ");
                console.log("addFeature for: " + key);

                // check if it already exists
                var existingTokens = $scope.featureList[key];

                if (!existingTokens) {
                    var request = UserFeatures.add(tokens);
                    if (request) {
                        usSpinnerService.spin('vector-spinner');
                        request.then(function() {
                            usSpinnerService.stop('vector-spinner');
                            var featureId = UserFeatures.data;
                            $scope.featureList[key] = {
                                id: featureId,
                                tokens: tokens
                            };
                        });
                    }
                }
                else {
                    console.log("feature already exists: " + key);
                }

                $scope.clickStartTokenItem = undefined;
                $scope.selectedCharStart = -1;
                $scope.selectedCharEnd = -1;
                $scope.selectedTokens = null;
                $scope.selectedTokenIndices.clear();
            }
        };

        $scope.removeFeature = function(feature){
            if (feature){
                var key = feature.tokens.join(" ");
                console.log("removeFeature for: " + key);

                // check if it already exists
                var existingTokens = $scope.featureList[key];

                if (existingTokens) {

                    var request = UserFeatures.remove(feature.id);
                    if (request) {
                        usSpinnerService.spin('vector-spinner');
                        request.then(function() {
                            usSpinnerService.stop('vector-spinner');
                            delete $scope.featureList[key];
                        });
                    }
                }
                else {
                    console.log("feature does not exist: " + key);
                }
            }
        }
    };

    ViewController.$inject = [
        '$scope',
        'TextCoder.services.Dictionary',
        'TextCoder.services.SVMResult',
        'TextCoder.services.FeatureVector',
        'TextCoder.services.UserFeatures',
        'usSpinnerService'
    ];
    module.controller('TextCoder.controllers.ViewController', ViewController);

    module.directive('datetimeFormat', function() {
      return {
        require: 'ngModel',
        link: function(scope, element, attrs, ngModelController) {
          ngModelController.$parsers.push(function(data) {
            //convert data from view format to model format
            data = moment.utc(data, "YYYY-MM-DD HH:mm:ss");
            if (data.isValid()) return data.toDate();
            else return undefined;
          });

          ngModelController.$formatters.push(function(data) {
            //convert data from model format to view format
              if (data !== undefined) return moment.utc(data).format("YYYY-MM-DD HH:mm:ss"); //converted
              return data;
          });
        }
      }
    });

    module.directive('whenScrolled', function() {
        return function(scope, element, attr) {
            var raw = element[0];

            var checkBounds = function(evt) {
                if (Math.abs(raw.scrollTop + $(raw).height() - raw.scrollHeight) < 10) {
                    scope.$apply(attr.whenScrolled);
                }

            };
            element.bind('scroll load', checkBounds);
        };
    });

    module.directive('ngEnter', function () {
        return function (scope, element, attrs) {
            element.bind("keydown keypress", function (event) {
                if(event.which === 13) {
                    scope.$apply(function (){
                        scope.$eval(attrs.ngEnter);
                    });

                    event.preventDefault();
                }
            });
        };
    });
})();
<commit_msg>Remove unused vars<commit_after>(function () {
    'use strict';

    var module = angular.module('TextCoder.controllers', [
        'TextCoder.services',
        'angularSpinner',
        'angucomplete-alt',
        'smart-table'
    ]);

    module.config(['$interpolateProvider', function ($interpolateProvider) {
        $interpolateProvider.startSymbol('{$');
        $interpolateProvider.endSymbol('$}');
    }]);

    module.config(['usSpinnerConfigProvider', function (usSpinnerConfigProvider) {
        usSpinnerConfigProvider.setDefaults({
            color: '#111'
        });
    }]);

    var DictionaryController = function ($scope, Dictionary) {
        $scope.Dictionary = Dictionary;

    };
    DictionaryController.$inject = [
        '$scope',
        'TextCoder.services.Dictionary'
    ];
    module.controller('TextCoder.controllers.DictionaryController', DictionaryController);

    var ViewController = function ($scope, Dictionary, SVMResult, FeatureVector, UserFeatures, usSpinnerService) {

        $scope.spinnerOptions = {
            radius: 20,
            width: 6,
            length: 10,
            color: "#000000"
        };
        var dist_max_height = 20; // in pixel

        $scope.svm_results = undefined;
        $scope.vector = undefined;
        $scope.features = [];

        $scope.load = function(){
            var request = SVMResult.load(Dictionary.id);
            if (request) {
                usSpinnerService.spin('table-spinner');
                request.then(function() {
                    usSpinnerService.stop('table-spinner');
                    SVMResult.dist_scale.range([0, dist_max_height]);
                    $scope.svm_results = SVMResult.data;
                });
            }

        };

        // load the svm results
        $scope.load();

        $scope.style = function(code){
            var colors = ["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"];
            var css = {
                'background-color' : 'none',
                'color': 'black'
            };
            var code_order = (Math.floor(code.order / 2));
            if (code_order  < colors.length ){
                css['background-color'] = colors[colors.length - code_order  - 1];
                if ( code_order  < 3)
                    css['color'] = '#ccc';
            }
            return css;
        };
        $scope.dist = function(code){
            var css = {
                'background-color': 'steelblue',
                'width' : 15,
                'height': SVMResult.dist_scale(code.train_count)
            };
            return css;
        };
        $scope.on_off = function(count){
            var css = {
                'background-color' : 'none',
                'color': 'black'
            };
            if (count > 0){
                css['background-color'] = "#fee0d2";
                //css['color'] = '#ccc';
            }
            return css;
        };
        $scope.active = function(tid){
            return ($scope.vector && $scope.vector.message.id == tid) ? "active" : "";
        };

        $scope.load_vector = function(tid){
            var request = FeatureVector.load(tid);
            if (request) {
                usSpinnerService.spin('vector-spinner');
                request.then(function() {
                    usSpinnerService.stop('vector-spinner');
                    $scope.vector = FeatureVector.data;

                    // TODO (jinasuh): Replace with actual data from service
                    var text = "RT @iNialls_Girl: R.I.P. to the 8 year old boy who died in Bostons explosions, while running for the Sandy Hook kids. #PrayForBoston ht ...";
                    var characters = text.split("");

                    var tokens = ["rt",
                                "@inialls_girl",
                                ":",
                                "r.i.p.",
                                "to",
                                "the",
                                "8",
                                "year",
                                "old",
                                "boy",
                                "who",
                                "died",
                                "in",
                                "bostons",
                                "explosions",
                                ",",
                                "while",
                                "running",
                                "for",
                                "the",
                                "sandy",
                                "hook",
                                "kids",
                                ".",
                                "#prayforboston",
                                "ht",
                                "..."];

                    var tokenItems = [];
                    var charToToken = [];

                    var lowerText = text.toLowerCase();
                    var currentIndex = 0;
                    for (var i = 0; i < tokens.length; i++)
                    {
                        var token = tokens[i];
                        if (token != null && token.length > 0)
                        {
                            var foundIndex = lowerText.substr(currentIndex).indexOf(token) + currentIndex;

                            var tokenItem = {
                                text: token,
                                index: i
                            };

                            currentIndex = foundIndex;
                            tokenItem.startIndex = currentIndex;
                            currentIndex += token.length - 1;
                            tokenItem.endIndex = currentIndex;

                            tokenItems.push(tokenItem);

                            for (var j = tokenItem.startIndex; j <= tokenItem.endIndex; j++)
                            {
                                charToToken[j] = i;
                            }
                        }
                    }

                    $scope.vector.message.text = text;
                    $scope.vector.message.tokens = tokenItems;
                    $scope.vector.message.characters = characters;
                    $scope.vector.message.charToToken = charToToken;
                });
            }
        };

        $scope.getter = {
            'vector': function(feature){
                return $scope.vector.feature_vector[feature.word_index];
            }
        };

        // Feature selection logic and states
        $scope.hoveredCharStart = -1;
        $scope.hoveredCharEnd = -1;
        $scope.clickStartTokenItem = undefined;
        $scope.selectedTokens = undefined;
        $scope.selectedTokenIndices = new Map();

        $scope.featureList = {};

        var updateSelection = function(startIndex, endIndex, isSelected, shouldClear) {
            if (shouldClear) {
                $scope.selectedTokenIndices.clear();
            }

            for (var i = startIndex; i <= endIndex; i++) {
                var existing = $scope.selectedTokenIndices.get(i);
                if (existing == i && !isSelected) {
                    $scope.selectedTokenIndices.delete(i);
                }
                else if (existing != i && isSelected) {
                    $scope.selectedTokenIndices.set(i, i);
                }
            }

            // TODO: if the previous or next token is selected, also update the selection for the character (space) in between.
            //console.log($scope.selectedTokenIndices.values());
        };

        $scope.onCharMouseEnter = function(charIndex){
            //console.log("onCharMouseEnter:" + charIndex);

            if ($scope.vector && $scope.vector.message){
                var tokenIndex = $scope.vector.message.charToToken[charIndex];

                if (tokenIndex != undefined && $scope.vector.message.tokens[tokenIndex] != undefined) {
                    var tokenItem = $scope.vector.message.tokens[tokenIndex];
                    $scope.hoveredCharStart = tokenItem.startIndex;
                    $scope.hoveredCharEnd = tokenItem.endIndex;

                    // If we're in the middle of selection, update selected char indices
                    if ($scope.clickStartTokenItem != undefined){
                        if (tokenIndex < $scope.clickStartTokenItem.index){
                            updateSelection(tokenIndex, $scope.clickStartTokenItem.index, true, true);
                        }
                        else if (tokenIndex > $scope.clickStartTokenItem.index){
                            updateSelection($scope.clickStartTokenItem.index, tokenIndex, true, true);
                        }
                    }
                }
                else {
                    $scope.hoveredCharStart = -1;
                    $scope.hoveredCharEnd = -1;
                }
            }
        };

        $scope.onCharMouseLeave = function(charIndex){
            //console.log("onCharMouseLeave:" + charIndex);

            $scope.hoveredCharStart = -1;
            $scope.hoveredCharEnd = -1;
        };

        $scope.onCharMouseDown = function(charIndex, event){
            //console.log("onCharMouseDown:" + charIndex);

            if ($scope.vector && $scope.vector.message) {

                var tokenIndex = $scope.vector.message.charToToken[charIndex];

                if (tokenIndex != undefined && $scope.vector.message.tokens[tokenIndex] != undefined) {

                    var tokenItem = $scope.vector.message.tokens[tokenIndex];

                    var ctrlClick = event.ctrlKey || (event.metaKey && !event.ctrlKey);
                    // if there was a selection at this tokenIndex and mouse was clicked with command/ctrl button,
                    // clear the selection on this token index
                    if ($scope.selectedTokenIndices.get(tokenIndex) == tokenIndex && ctrlClick) {
                        $scope.clickStartTokenItem = undefined;
                        updateSelection(tokenIndex, tokenIndex, false, false);
                    }
                    else {
                        $scope.clickStartTokenItem = tokenItem;
                        updateSelection(tokenIndex, tokenIndex, true, !ctrlClick);
                    }
                }
                else {
                    $scope.clickStartTokenItem = undefined;
                    $scope.selectedTokenIndices.clear();
                }
            }
        };

        $scope.onCharMouseUp = function(charIndex) {
            $scope.clickStartTokenItem = undefined;
            $scope.selectedTokens = undefined;

            if ($scope.selectedTokenIndices.size > 0) {
                if ($scope.vector && $scope.vector.message) {

                    // Get sorted list of selected token indices
                    var indices = [];
                    $scope.selectedTokenIndices.forEach(function (val) {
                        indices.push(val);
                    });
                    indices.sort(function (a, b) {
                        return a - b;
                    });

                    var tokens = [];
                    var currentTokenIndex = -1;
                    for (var i = 0; i < indices.length; i++) {
                        var tokenIndex = indices[i];

                        if (tokenIndex != currentTokenIndex) {
                            tokens.push($scope.vector.message.tokens[tokenIndex].text);
                            currentTokenIndex = tokenIndex;
                        }
                    }

                    $scope.selectedTokens = tokens;
                }
            }
        };

        $scope.charStyle = function(charIndex){
            var style = {};
            if (charIndex >= $scope.hoveredCharStart && charIndex <= $scope.hoveredCharEnd){
                style["background"] = "#ffcc99";
            }

            if ($scope.vector && $scope.vector.message) {
                var tokenIndex = $scope.vector.message.charToToken[charIndex];
                if (tokenIndex != undefined && $scope.selectedTokenIndices.get(tokenIndex) == tokenIndex) {
                    style["background"] = "#ff6600";
                }
            }
            return style;
        };

        $scope.addFeature = function(tokens){
            if (tokens && tokens.length > 0){

                var key = tokens.join(" ");
                console.log("addFeature for: " + key);

                // check if it already exists
                var existingTokens = $scope.featureList[key];

                if (!existingTokens) {
                    var request = UserFeatures.add(tokens);
                    if (request) {
                        usSpinnerService.spin('vector-spinner');
                        request.then(function() {
                            usSpinnerService.stop('vector-spinner');
                            var featureId = UserFeatures.data;
                            $scope.featureList[key] = {
                                id: featureId,
                                tokens: tokens
                            };
                        });
                    }
                }
                else {
                    console.log("feature already exists: " + key);
                }

                $scope.clickStartTokenItem = undefined;
                $scope.selectedTokens = null;
                $scope.selectedTokenIndices.clear();
            }
        };

        $scope.removeFeature = function(feature){
            if (feature){
                var key = feature.tokens.join(" ");
                console.log("removeFeature for: " + key);

                // check if it already exists
                var existingTokens = $scope.featureList[key];

                if (existingTokens) {

                    var request = UserFeatures.remove(feature.id);
                    if (request) {
                        usSpinnerService.spin('vector-spinner');
                        request.then(function() {
                            usSpinnerService.stop('vector-spinner');
                            delete $scope.featureList[key];
                        });
                    }
                }
                else {
                    console.log("feature does not exist: " + key);
                }
            }
        }
    };

    ViewController.$inject = [
        '$scope',
        'TextCoder.services.Dictionary',
        'TextCoder.services.SVMResult',
        'TextCoder.services.FeatureVector',
        'TextCoder.services.UserFeatures',
        'usSpinnerService'
    ];
    module.controller('TextCoder.controllers.ViewController', ViewController);

    module.directive('datetimeFormat', function() {
      return {
        require: 'ngModel',
        link: function(scope, element, attrs, ngModelController) {
          ngModelController.$parsers.push(function(data) {
            //convert data from view format to model format
            data = moment.utc(data, "YYYY-MM-DD HH:mm:ss");
            if (data.isValid()) return data.toDate();
            else return undefined;
          });

          ngModelController.$formatters.push(function(data) {
            //convert data from model format to view format
              if (data !== undefined) return moment.utc(data).format("YYYY-MM-DD HH:mm:ss"); //converted
              return data;
          });
        }
      }
    });

    module.directive('whenScrolled', function() {
        return function(scope, element, attr) {
            var raw = element[0];

            var checkBounds = function(evt) {
                if (Math.abs(raw.scrollTop + $(raw).height() - raw.scrollHeight) < 10) {
                    scope.$apply(attr.whenScrolled);
                }

            };
            element.bind('scroll load', checkBounds);
        };
    });

    module.directive('ngEnter', function () {
        return function (scope, element, attrs) {
            element.bind("keydown keypress", function (event) {
                if(event.which === 13) {
                    scope.$apply(function (){
                        scope.$eval(attrs.ngEnter);
                    });

                    event.preventDefault();
                }
            });
        };
    });
})();
<|endoftext|>


<commit_before>define([
        'dojo/_base/declare',
        'dojo/_base/lang',

        'dijit/_WidgetBase',
        'dijit/_TemplatedMixin',
        'dijit/_WidgetsInTemplateMixin',

        'dojo/text!app/templates/Leaderboard.html',
        'dojo/text!app/templates/LeaderboardTemplate.html',
        'dojo/text!app/templates/LeaderItemTemplate.html',

        'mustache/mustache',

        'esri/request'
    ],

    function(
        declare,
        lang,

        _WidgetBase,
        _TemplatedMixin,
        _WidgetsInTemplateMixin,

        template,
        leaderboardTemplate,
        leaderboardItemTemplate,

        mustache,

        request
    ) {
        // summary:
        //      Handles retrieving and displaying the data in the popup.
        return declare("app.leaderboard", [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
            widgetsInTemplate: true,
            templateString: template,
            baseClass: 'leaderboard',

            // the data returned by the query to the url
            data: null,

            // the url to query for the leaderboard data
            url: null,

            constructor: function() {
                console.log(this.declaredClass + "::constructor", arguments);
            },
            postCreate: function() {
                // summary:
                //      dom is ready
                console.log(this.declaredClass + "::postCreate", arguments);

                this.inherited(arguments);

                this.boardTemplate = mustache.compile(leaderboardTemplate);
                this.boardItem = mustache.compile(leaderboardItemTemplate);

                this.wireEvents();

                if (this.url) {
                    request(this.url, {
                        //jsonp: 'callback'
                    });
                    //.then(lang.hitch(this, this.onRequestComplete), lang.hitch(this, this.onRequestFail));

                    return;
                }

                this.onRequestComplete(this.data);
            },
            onRequestComplete: function(json) {
                // summary:
                //      callback for request
                // json: Object
                console.log(this.declaredClass + "::onRequestComplete", arguments);

                this.boardTemplate(json);
            },
            onRequestFail: function(err) {
                // summary:
                //      fail callback for ajax request
                // err: Error
                console.log(this.declaredClass + "::onRequestFail", arguments);

                window.alert(err);
            },
            wireEvents: function() {
                // param: type or return: type
                console.log(this.declaredClass + "::wireEvents", arguments);

            },
            show: function() {
                // summary:
                //      description
                console.log(this.declaredClass + "::show", arguments);

            },
            hide: function() {
                // summary:
                //      description
                console.log(this.declaredClass + "::hide", arguments);

            }
        });
    });<commit_msg>xhr request linkup<commit_after>define([
        'dojo/_base/declare',
        'dojo/_base/lang',

        'dojo/Deferred',

        'dijit/_WidgetBase',
        'dijit/_TemplatedMixin',
        'dijit/_WidgetsInTemplateMixin',

        'dojo/text!app/templates/Leaderboard.html',
        'dojo/text!app/templates/LeaderboardTemplate.html',
        'dojo/text!app/templates/LeaderItemTemplate.html',

        'mustache/mustache',

        'esri/request'
    ],

    function(
        declare,
        lang,

        Deferred,

        _WidgetBase,
        _TemplatedMixin,
        _WidgetsInTemplateMixin,

        template,
        leaderboardTemplate,
        leaderboardItemTemplate,

        mustache,

        request
    ) {
        // summary:
        //      Handles retrieving and displaying the data in the popup.
        return declare("app.leaderboard", [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
            widgetsInTemplate: true,
            templateString: template,
            baseClass: 'leaderboard',

            // the data returned by the query to the url
            data: null,

            // the url to query for the leaderboard data
            url: null,

            constructor: function() {
                console.log(this.declaredClass + "::constructor", arguments);
            },
            postCreate: function() {
                // summary:
                //      dom is ready
                console.log(this.declaredClass + "::postCreate", arguments);

                this.inherited(arguments);

                this.boardTemplate = mustache.compile(leaderboardTemplate);
                this.boardItem = mustache.compile(leaderboardItemTemplate);

                this.wireEvents();

                this.getLeaderboard().then(lang.hitch(this,
                    function(content) {
                        this.set('containerDiv', content);
                    }));
            },
            _setContainerDivAttr: {
                node: 'containerDiv',
                type: 'innerHTML'
            },
            getLeaderboard: function() {
                console.log(this.declaredClass + "::getLeaderboard", arguments);

                this.xhrDeferred = new dojo.Deferred();

                if (this.url) {
                    console.log('requesting data');
                    request({
                        url: this.url,
                        handleAs: "json"
                    }).then(lang.hitch(this, this.onRequestComplete),
                        lang.hitch(this, this.onRequestFail));

                    return this.xhrDeferred;
                }

                this.onRequestComplete(this.data);

                return this.xhrDeferred;
            },
            onRequestComplete: function(json) {
                // summary:
                //      callback for request
                // json: Object
                console.log(this.declaredClass + "::onRequestComplete", arguments);

                this.xhrDeferred.resolve(this.boardTemplate(json));
            },
            onRequestFail: function(err) {
                // summary:
                //      fail callback for ajax request
                // err: Error
                console.log(this.declaredClass + "::onRequestFail", arguments);

                window.alert(err);
            },
            wireEvents: function() {
                // param: type or return: type
                console.log(this.declaredClass + "::wireEvents", arguments);

            },
            show: function() {
                // summary:
                //      description
                console.log(this.declaredClass + "::show", arguments);

            },
            hide: function() {
                // summary:
                //      description
                console.log(this.declaredClass + "::hide", arguments);

            }
        });
    });<|endoftext|>


<commit_before>import React, {createClass} from 'react'
import {connectRange} from 'react-instantsearch/connectors'
import Rheostat from 'rheostat'

import './style.scss'

const Range = createClass({
  getInitialState () {
    const { props } = this
    const { min, max } = props
    const value = props.currentRefinement
    return {min, max, value}
  },

  onValuesUpdated (state) {
    const value = {
      min: state.values[0],
      max: state.values[1]
    }

    this.setState({
      min: state.min,
      max: state.max,
      value: value
    })
  },

  onChange (state) {
    const { min, max, refine } = this.props

    const value = {
      min: state.values[0],
      max: state.values[1]
    }

    if (value.min !== min || value.max !== max) {
      refine({min: value.min, max: value.max})
    }
  },

  render () {
    const { min, max, label, title } = this.props
    const { onChange, onValuesUpdated, state } = this

    return (

        {title}
        <Rheostat
          className='mh3'
          min={min}
          max={max}
          values={[state.value.min, state.value.max]}
          onValuesUpdated={onValuesUpdated}
          onChange={onChange}
        />

            {state.value.min}{label}

            {state.value.max}{label}

    )
  }
})

export default connectRange(Range)
<commit_msg>Fix Range<commit_after>import React, {createClass} from 'react'
import {connectRange} from 'react-instantsearch/connectors'
import Rheostat from 'rheostat'

import './style.scss'

const Range = createClass({
  getInitialState () {
    const { props } = this
    const { min, max, currentRefinement } = props
    const value = currentRefinement
    return {min, max, value}
  },

  onValuesUpdated (state) {
    const value = {
      min: state.values[0],
      max: state.values[1]
    }

    this.setState({
      min: state.min,
      max: state.max,
      value: value
    })
  },

  onChange (state) {
    const { min, max, refine } = this.props

    const value = {
      min: state.values[0],
      max: state.values[1]
    }

    if (value.min !== min || value.max !== max) {
      refine({min: value.min, max: value.max})
    }
  },

  render () {
    const { onChange, onValuesUpdated, state, props } = this
    const { min, max, label, title, currentRefinement } = props

    return (

        {title}
        <Rheostat
          className='mh3'
          min={min}
          max={max}
          values={[currentRefinement.min, currentRefinement.max]}
          onValuesUpdated={onValuesUpdated}
          onChange={onChange}
        />

            {state.value.min}{label}

            {state.value.max}{label}

    )
  }
})

export default connectRange(Range)
<|endoftext|>