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

define(['jquery', 'api', 'input'], function($, api, input) {
  "use strict";

  var COMPLETION_DELAY = 50;

  function repeat(s,n) {
    while (s.length < n) { s = s + s; }
    return s.substr(0,n);
  }

  function repeatSpan(s,n) {
    while (s.length < n) { s = s + s; }
    var e = $('

');
    e.text(s.substr(0,n));
    return e;
  }

  function commonPrefix(w1, w2) {
    var len = Math.min(w1.length, w2.length);
    for (var i = 0; i < len; i++) {
      if (w1[i] != w2[i]) break;
    }
    return w1.substr(0, i);
  }

  var annoElem = $('#annotations');
  var annotations = [];
  var currentShowingElem = null;
  var completionSpan;
  var completionArray;
  var completionCommonPrefix;
  var completionElem;

  var commandline = $('#commandline');

  function clearAnnotations() {
    annoElem.empty();
    if (currentShowingElem) {
      currentShowingElem.hide();
      currentShowingElem = null;
    }
    annotations = [];
    completionSpan = null;
    completionArray = null;
    completionCommonPrefix = null;
    completionElem = null;
  }

  function updateAnnotations(comp) {
    clearAnnotations();

    var i = 1;
    var spans = comp.spans || [];
    spans.forEach(function(span) {
      var m = "";
      var c = [];
      span.annotations.forEach(function(anno) {
        if (anno.expansion) {
          m += 'expands to ' + anno.expansion;
        }
        else if (anno.commandType) {
          m += anno.commandType + " command"
          if (anno.path) {
            m += " @ " + anno.path
          }
        }
        else if (anno.command) {
          m += anno.command + "\n" + anno.synopsis + "\n";
        }
        else if (anno.option) {
          m += anno.option ;
        }
        else if (anno.unused) {
          m += "unused";
        }
        else if (anno.completions) {
          c = c.concat(anno.completions);
        }
        m += "\n";
      });

      m = m.trim()
      if (m || c.length) {
        var a = { start: span.start, end: span.end };

        if (i < span.start) {
          annoElem.append(repeatSpan(' ', span.start - i));
          i = span.start;
        }
        var blockElem = repeatSpan(' ', span.end - span.start);
        blockElem.addClass('annotation');
        annoElem.append(blockElem);
        i = span.end;

        if (m) {
          var msgElem = $('', { "class": "message" });
          msgElem.text(m);
          msgElem.hide();
          blockElem.append(msgElem);
          a.msgElem = msgElem;
        }

        if (c.length) {
          completionSpan = a;
          completionArray = c;
          completionCommonPrefix = c[0];

          completionElem = $('

', { "class": "completions" });
          c.forEach(function(t) {
            var textElem = $('

');
            textElem.text(t);
            completionElem.append(textElem);
            completionCommonPrefix = commonPrefix(completionCommonPrefix, t);
          });
          completionElem.hide();
          blockElem.append(completionElem);
        }

        annotations.push(a);
      }
    });
  }

  function commandChange() {
    if (completing) return;

    var loc = commandline[0].selectionStart;
    if (typeof loc !== 'number') return;

    var nextA;
    for (var i = 0; i < annotations.length; i += 1) {
      var a = annotations[i];
      if (a.start <= loc && loc < a.end) {
        nextA = a;
        break;
      }
    }

    if (nextA) {
      if (nextA.msgElem != currentShowingElem) {
        if (currentShowingElem) currentShowingElem.hide('fast');
        currentShowingElem = nextA.msgElem;
        if (currentShowingElem) currentShowingElem.show('fast');
      }
    }

  }

  var completing = false;
  var completingPrefix;
  var completingOriginal
  var completingPostfix;
  var completingFocus;

  function startCompletions() {
    if (!completionSpan) return;

    completing = true;
    clearTimeout(checkTimer);

    var input = commandline.val();
    completingPrefix = input.substring(0, completionSpan.start - 1);
    completingOriginal = input.substring(completionSpan.start - 1,
                                          completionSpan.end);
    completingPostfix = input.substring(completionSpan.end);

    insertCompletion(completionCommonPrefix);
    $('.completions').show();
  }

  function insertCompletion(text) {
    commandline.val(completingPrefix + text + completingPostfix);
      // TODO: should shell escape test here
    var s = completingPrefix.length + text.length;
    commandline[0].setSelectionRange(s,s);
  }

  function nextCompletion(dir) {
    var nextFocus;
    if (completingFocus) {
      var oldFocus = completingFocus;
      switch (dir) {
        case -1: nextFocus = oldFocus.prevAll('li').first(); break;
        case  1: nextFocus = oldFocus.nextAll('li').first(); break;
      }
      oldFocus.removeClass('focus');
    }
    if (!nextFocus) {
      switch(dir) {
        case -1: nextFocus = completionElem.find('li').last(); break;
        case  1: nextFocus = completionElem.find('li').first(); break;
      }
    }
    if (nextFocus && nextFocus.length > 0) {
      nextFocus.addClass('focus');
      completingFocus = nextFocus;
      insertCompletion(nextFocus.text());
    } else {
      completingFocus = null;
    }
  }

  function finishCompletion() {
    $('.completions').hide();
    completing = false;
    commandline.focus();
    requestRunComplete();
  }

  function finishCompletionAll() {
    insertCompletion(completionArray.join(' ') + ' ');
    finishCompletion();
  }

  function cancelCompletion() {
    insertCompletion(completingOriginal);
    finishCompletion();
  }

  var triggerCompletionKeydown = input.keyHandler({
    'TAB':            function() { startCompletions(); },
  });

  var completionModeKeydown = input.keyHandler({
    bindings: {
      'DOWN, TAB':          function() { nextCompletion(1); },
      'UP, SHIFT+TAB':      function() { nextCompletion(-1); },
      'RETURN':             function() { finishCompletion(); },
      'ASTERISK, EQUALS, EQUALS2':
                            function() { finishCompletionAll(); },
      'ESCAPE':             function() { cancelCompletion(); }
    },
    default: function() { finishCompletion(); return input.PASS; }
  });

  function keydown(e) {
    if (!completing) {
      return triggerCompletionKeydown(e);
    } else {
      return completionModeKeydown(e);
    }
  }

  var checkTimer = null;
  var lastCheckedCommandLine;

  function requestRunComplete() {
    clearTimeout(checkTimer);
    if (completing) return;
    checkTimer = setTimeout(runComplete, COMPLETION_DELAY);
  }

  function runComplete() {
    var input = commandline.val();
    if (input === lastCheckedCommandLine) return;
    lastCheckedCommandLine = input;

    input = input.replace(/'/g,"'\\''");
    var loc = commandline[0].selectionStart;
    loc = (typeof loc === 'number') ? ' -c ' + loc : '';
    var cmd = "complete" + loc + " '" + input + "'";
    api.runStatus(cmd, function (d) {
      if ('jsonout' in d) {
        d.jsonout.forEach(updateAnnotations);
      }
      commandChange();
    });
  }

  return {
    clearAnnotations: clearAnnotations,
    commandChange: commandChange,
    keydown: keydown,
    requestRunComplete: requestRunComplete
  }
});
<commit_msg>fixup to completion JS<commit_after>// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

define(['jquery', 'api', 'input'], function($, api, input) {
  "use strict";

  var COMPLETION_DELAY = 50;

  function repeat(s,n) {
    while (s.length < n) { s = s + s; }
    return s.substr(0,n);
  }

  function repeatSpan(s,n) {
    while (s.length < n) { s = s + s; }
    var e = $('

');
    e.text(s.substr(0,n));
    return e;
  }

  function commonPrefix(w1, w2) {
    var len = Math.min(w1.length, w2.length);
    for (var i = 0; i < len; i++) {
      if (w1[i] != w2[i]) break;
    }
    return w1.substr(0, i);
  }

  var annoElem = $('#annotations');
  var annotations = [];
  var currentShowingElem = null;
  var completionSpan;
  var completionArray;
  var completionCommonPrefix;
  var completionElem;

  var commandline = $('#commandline');

  function clearAnnotations() {
    annoElem.empty();
    if (currentShowingElem) {
      currentShowingElem.hide();
      currentShowingElem = null;
    }
    annotations = [];
    completionSpan = null;
    completionArray = null;
    completionCommonPrefix = null;
    completionElem = null;
  }

  function updateAnnotations(comp) {
    clearAnnotations();

    var i = 1;
    var spans = comp.spans || [];
    spans.forEach(function(span) {
      var m = "";
      var c = [];
      span.annotations.forEach(function(anno) {
        if (anno.expansion) {
          m += 'expands to ' + anno.expansion;
        }
        else if (anno.commandType) {
          m += anno.commandType + " command"
          if (anno.path) {
            m += " @ " + anno.path
          }
        }
        else if (anno.command) {
          m += anno.command + "\n" + anno.synopsis + "\n";
        }
        else if (anno.option) {
          m += anno.option ;
        }
        else if (anno.unused) {
          m += "unused";
        }
        else if (anno.completions) {
          c = c.concat(anno.completions);
        }
        m += "\n";
      });

      m = m.trim()
      if (m || c.length) {
        var a = { start: span.start, end: span.end };

        if (i < span.start) {
          annoElem.append(repeatSpan(' ', span.start - i));
          i = span.start;
        }
        var blockElem = repeatSpan(' ', span.end - span.start);
        blockElem.addClass('annotation');
        annoElem.append(blockElem);
        i = span.end;

        if (m) {
          var msgElem = $('', { "class": "message" });
          msgElem.text(m);
          msgElem.hide();
          blockElem.append(msgElem);
          a.msgElem = msgElem;
        }

        if (c.length) {
          completionSpan = a;
          completionArray = c;
          completionCommonPrefix = c[0];

          completionElem = $('

', { "class": "completions" });
          c.forEach(function(t) {
            var textElem = $('

');
            textElem.text(t);
            completionElem.append(textElem);
            completionCommonPrefix = commonPrefix(completionCommonPrefix, t);
          });
          completionElem.hide();
          blockElem.append(completionElem);
        }

        annotations.push(a);
      }
    });
  }

  function commandChange() {
    if (completing) return;

    var loc = commandline[0].selectionStart;
    if (typeof loc !== 'number') return;

    var nextA;
    for (var i = 0; i < annotations.length; i += 1) {
      var a = annotations[i];
      if (a.start <= loc && loc < a.end) {
        nextA = a;
        break;
      }
    }

    if (nextA) {
      if (nextA.msgElem != currentShowingElem) {
        if (currentShowingElem) currentShowingElem.hide('fast');
        currentShowingElem = nextA.msgElem;
        if (currentShowingElem) currentShowingElem.show('fast');
      }
    }

  }

  var completing = false;
  var completingPrefix;
  var completingOriginal
  var completingPostfix;
  var completingFocus;

  function startCompletions() {
    if (!completionSpan) return;

    completing = true;
    clearTimeout(checkTimer);

    var input = commandline.val();
    completingPrefix = input.substring(0, completionSpan.start - 1);
    completingOriginal = input.substring(completionSpan.start - 1,
                                          completionSpan.end);
    completingPostfix = input.substring(completionSpan.end);
    completingFocus = null;

    insertCompletion(completionCommonPrefix);
    if (currentShowingElem) currentShowingElem.hide();
    currentShowingElem = $('.completions');
    if (currentShowingElem) currentShowingElem.show();
  }

  function insertCompletion(text) {
    commandline.val(completingPrefix + text + completingPostfix);
      // TODO: should shell escape test here
    var s = completingPrefix.length + text.length;
    commandline[0].setSelectionRange(s,s);
  }

  function nextCompletion(dir) {
    var nextFocus;
    if (completingFocus) {
      var oldFocus = completingFocus;
      switch (dir) {
        case -1: nextFocus = oldFocus.prevAll('li').first(); break;
        case  1: nextFocus = oldFocus.nextAll('li').first(); break;
      }
      oldFocus.removeClass('focus');
    }
    if (!nextFocus) {
      switch(dir) {
        case -1: nextFocus = completionElem.find('li').last(); break;
        case  1: nextFocus = completionElem.find('li').first(); break;
      }
    }
    if (nextFocus && nextFocus.length > 0) {
      nextFocus.addClass('focus');
      completingFocus = nextFocus;
      insertCompletion(nextFocus.text());
    } else {
      completingFocus = null;
    }
  }

  function finishCompletion() {
    $('.completions').hide();
    completing = false;
    completingFocus = null;
    currentShowingElem = null;
    commandline.focus();
    requestRunComplete();
  }

  function finishCompletionAll() {
    insertCompletion(completionArray.join(' ') + ' ');
    finishCompletion();
  }

  function cancelCompletion() {
    insertCompletion(completingOriginal);
    finishCompletion();
  }

  var triggerCompletionKeydown = input.keyHandler({
    'TAB':            function() { startCompletions(); },
  });

  var completionModeKeydown = input.keyHandler({
    bindings: {
      'DOWN, TAB':          function() { nextCompletion(1); },
      'UP, SHIFT+TAB':      function() { nextCompletion(-1); },
      'RETURN':             function() { finishCompletion(); },
      'ASTERISK, EQUALS, EQUALS2':
                            function() { finishCompletionAll(); },
      'ESCAPE':             function() { cancelCompletion(); }
    },
    default: function() { finishCompletion(); return input.PASS; }
  });

  function keydown(e) {
    if (!completing) {
      return triggerCompletionKeydown(e);
    } else {
      return completionModeKeydown(e);
    }
  }

  var checkTimer = null;
  var lastCheckedCommandLine;

  function requestRunComplete() {
    clearTimeout(checkTimer);
    if (completing) return;
    checkTimer = setTimeout(runComplete, COMPLETION_DELAY);
  }

  function runComplete() {
    var input = commandline.val();
    if (input === lastCheckedCommandLine) return;
    lastCheckedCommandLine = input;

    input = input.replace(/'/g,"'\\''");
    var loc = commandline[0].selectionStart;
    loc = (typeof loc === 'number') ? ' -c ' + loc : '';
    var cmd = "complete" + loc + " '" + input + "'";
    api.runStatus(cmd, function (d) {
      if ('jsonout' in d) {
        d.jsonout.forEach(updateAnnotations);
      }
      commandChange();
    });
  }

  return {
    clearAnnotations: clearAnnotations,
    commandChange: commandChange,
    keydown: keydown,
    requestRunComplete: requestRunComplete
  }
});
<|endoftext|>


<commit_before>var Q = require("q");

var utils = require("./utils");
var states = require("./states");
var State = states.State;
var StateError = states.StateError;
var EndState = states.EndState;

var events = require("./events");
var Eventable = events.Eventable;

var App = Eventable.extend(function(self, start_state_name, opts) {
    /**class:App(start_state_name[, opts])

    The main component defining a sandbox application. To be subclassed and
    given application spefic states and logic.

    :param string start_state_name:
        name of the initial state. New users will enter this
        state when they first interact with the sandbox
        application.
    :param opts.AppStates:
        Optional subclass of :class:`AppStates` to be used for creating
        and managing states.
    */
    Eventable.call(self);

    opts = utils.set_defaults({AppStates: AppStates});
    self.start_state_name = start_state_name;
    self.AppStates = AppStates;
    self.states = new self.AppStates(self);

    self.setup = function(im) {
        self.im = im;
        return self
            .states.setup()
            .then(function() {
                return self.init();
            })
            .then(function() {
                return self.emit.setup();
            });
    };

    self.init = function() {
        /**:App.init()

        Invoked just after setup has completed, and just before 'setup' event
        is fired to provide subclasses with a setup hook. May return a promise.
        */
    };
});

var AppStates = Eventable.extend(function(self, app) {
    /**class:AppStates(app)

    A set of states for a sandbox application. States may be either statically
    created via ``add.state``, dynamically loaded via ``add.creator`` (or via
    ``add`` for either), or completely dynamically defined by overriding
    ``create``.

    :param App app:
        the application associated with this set of states.
    */
    Eventable.call(self);

    self.creators = {};
    self.app = app;

    self.setup = function() {
        self.im = self.app.im;
        return Q(self.init()).then(function() {
            return self.emit.setup();
        });
    };

    self.init = function() {
        /**:AppStates.init()

        Invoked just after setup has completed, and just before 'setup' event
        is fired to provide subclasses with a setup hook. May return a promise.
        */
    };

    self.add = function(state_or_name) {
        /**:AppStates.add(state)

        Adds an already created state by delegating to
        :meth:`AppStates.add.state`.

        :param State state: the state to add
        */
        /**:AppStates.add(name, creator)

        Adds a state creator by delegating to :meth:`AppStates.add.creator`.

        :param State state: the state to add
        */
        return state_or_name instanceof State
            ? self.add.state.apply(self, arguments)
            : self.add.creator.apply(self, arguments);
    };

    self.add.state = function(state) {
        /**:AppStates.add.state(state)

        Adds an already created state.

        :param State state: the state to add
        */
        self.add.creator(state.name, function() {
            return state;
        });
    };

    self.add.creator = function(name, creator) {
        /**:AppStates.add.creator(name, creator)

         Adds a state creator. Invoked by :meth:`AppStates.create`, or
         throws an error if a creator is already registered under the given
         state name.

        :param string state_name: name of the state
        :param function creator:
            A function ``func(state_name)`` for creating the state. This
            function should take the state name should return a state object
            either directly or via a promise.
        */
        if (name in self.creators) {
            throw new StateError("Duplicate state '" + name + "'");
        }

        self.creators[name] = creator;
    };

    self.remove = function(name) {
        /**:App.remove(name)

        Removes an added state or state creator.

        :param string name: name of the state or state creator
        */
        delete self.creators[name];
    };

    self.check = function(state, name) {
        /**AppStates.check(state, name)

        Used by :meth:`AppStates.create` to ensure that an invoked
        state creator has constructed a valid state.

        :param State state:
            The created state
        :param string name:
            The state name associated with the creator that created the state
        */
        function check(truth, fail_message) {
            if (!truth) {
                throw new StateError(fail_message);
            }
        }

        check(state instanceof State, [
            "Creator for state '" + name + "' should create a state,",
            "but instead created something of type '" + typeof state + "'"
        ].join(' '));

        check(state.name == name || state.name == '__error__', [
            "Creator for state '" + name + "' created a state with",
            "a different name: '" + state.name + "'"
        ].join(' '));
    };

    self.create = function(name, opts) {
        /**:AppStates.create(name, opts)

        Creates the given state represented by the given state name by
        delegating to the associated state creator.

        :param string name:
            the name of the state to create.
        :param object opts:
            Options for the state to be created. Optional, state creators
            can use this but don't have to.

        If no creator is found for the requested state name, we create a start
        state instead.

        This function returns a promise.

        It may be overridden by :class:`AppStates` subclasses that wish
        to provide a completely dynamic set of states.
        */
        var creator;
        opts = opts || {};

        if (name == self.app.start_state_name) {
            creator = self.creators.__start__;
        }
        else if (name in self.creators) {
            creator = self.creators[name];
        }
        else {
            self.im.log(
                "Unknown state '" + name + "'. Switching to" +
                " start state '" + self.app.start_state_name + "'.");

            creator = self.creators.__start__;
            name = self.app.start_state_name;
        }

        return Q(creator.call(self.app, name, opts))
            .then(function(state) {
                self.check(state, name);
                return state;
            })
            .catch(function(e) {
                self.im.log(e.message);
                return self.create('__error__');
            });
    };

    self.creators.__error__ = function(name) {
        /**:AppStates.creators.__error__(name)

        Creates the fallback error state.

        :param string name:
            the name of the state for which an error occurred.

        This default implementation creates an EndState with name
        ``name`` and content *"An error occurred. Please try again later"*.

        The end state created has the next state set to ``null``. When the
        state receives input, it will invoke :meth:`UserStateData.change` to
        change the user's current state. Since the state given to it is
        ``null``, it will instead stay on the current state.

        If we are dealing with a new user, then the :class:`InteractionMachine`
        will have requested the start state to have been created. If the start
        state does not exist, we will end up here again, ensuring the same
        message will be displayed.
        */
        return new EndState(name, {
            next: null,
            text: "An error occurred. Please try again later."
        });
    };

    self.creators.__start__ = function(name) {
        /**:AppStates.creators.__start__(name)

        :param string name:
            the name of the start state.
        :param InteractionMachine im:
            the interaction machine the start state is for.

        The default implemenation looks up a creator for the state named
        ``name`` and calls that. If no such creator exists, it uses
        :meth:`App.creators.__error__` instead.
        */
        var creator = self.creators[name];

        if (!creator) {
            self.im.log([
                "Unknown start state '" + name + "'.",
                "Switching to error state."].join(' '));

            creator = self.creators.__error__;
            name = '__error__';
        }

        return creator.call(self.app, name);
    };
});

this.App = App;
this.AppStates = AppStates;
<commit_msg>Less confusing opts param description in AppStates.create()'s docstring<commit_after>var Q = require("q");

var utils = require("./utils");
var states = require("./states");
var State = states.State;
var StateError = states.StateError;
var EndState = states.EndState;

var events = require("./events");
var Eventable = events.Eventable;

var App = Eventable.extend(function(self, start_state_name, opts) {
    /**class:App(start_state_name[, opts])

    The main component defining a sandbox application. To be subclassed and
    given application spefic states and logic.

    :param string start_state_name:
        name of the initial state. New users will enter this
        state when they first interact with the sandbox
        application.
    :param opts.AppStates:
        Optional subclass of :class:`AppStates` to be used for creating
        and managing states.
    */
    Eventable.call(self);

    opts = utils.set_defaults({AppStates: AppStates});
    self.start_state_name = start_state_name;
    self.AppStates = AppStates;
    self.states = new self.AppStates(self);

    self.setup = function(im) {
        self.im = im;
        return self
            .states.setup()
            .then(function() {
                return self.init();
            })
            .then(function() {
                return self.emit.setup();
            });
    };

    self.init = function() {
        /**:App.init()

        Invoked just after setup has completed, and just before 'setup' event
        is fired to provide subclasses with a setup hook. May return a promise.
        */
    };
});

var AppStates = Eventable.extend(function(self, app) {
    /**class:AppStates(app)

    A set of states for a sandbox application. States may be either statically
    created via ``add.state``, dynamically loaded via ``add.creator`` (or via
    ``add`` for either), or completely dynamically defined by overriding
    ``create``.

    :param App app:
        the application associated with this set of states.
    */
    Eventable.call(self);

    self.creators = {};
    self.app = app;

    self.setup = function() {
        self.im = self.app.im;
        return Q(self.init()).then(function() {
            return self.emit.setup();
        });
    };

    self.init = function() {
        /**:AppStates.init()

        Invoked just after setup has completed, and just before 'setup' event
        is fired to provide subclasses with a setup hook. May return a promise.
        */
    };

    self.add = function(state_or_name) {
        /**:AppStates.add(state)

        Adds an already created state by delegating to
        :meth:`AppStates.add.state`.

        :param State state: the state to add
        */
        /**:AppStates.add(name, creator)

        Adds a state creator by delegating to :meth:`AppStates.add.creator`.

        :param State state: the state to add
        */
        return state_or_name instanceof State
            ? self.add.state.apply(self, arguments)
            : self.add.creator.apply(self, arguments);
    };

    self.add.state = function(state) {
        /**:AppStates.add.state(state)

        Adds an already created state.

        :param State state: the state to add
        */
        self.add.creator(state.name, function() {
            return state;
        });
    };

    self.add.creator = function(name, creator) {
        /**:AppStates.add.creator(name, creator)

         Adds a state creator. Invoked by :meth:`AppStates.create`, or
         throws an error if a creator is already registered under the given
         state name.

        :param string state_name: name of the state
        :param function creator:
            A function ``func(state_name)`` for creating the state. This
            function should take the state name should return a state object
            either directly or via a promise.
        */
        if (name in self.creators) {
            throw new StateError("Duplicate state '" + name + "'");
        }

        self.creators[name] = creator;
    };

    self.remove = function(name) {
        /**:App.remove(name)

        Removes an added state or state creator.

        :param string name: name of the state or state creator
        */
        delete self.creators[name];
    };

    self.check = function(state, name) {
        /**AppStates.check(state, name)

        Used by :meth:`AppStates.create` to ensure that an invoked
        state creator has constructed a valid state.

        :param State state:
            The created state
        :param string name:
            The state name associated with the creator that created the state
        */
        function check(truth, fail_message) {
            if (!truth) {
                throw new StateError(fail_message);
            }
        }

        check(state instanceof State, [
            "Creator for state '" + name + "' should create a state,",
            "but instead created something of type '" + typeof state + "'"
        ].join(' '));

        check(state.name == name || state.name == '__error__', [
            "Creator for state '" + name + "' created a state with",
            "a different name: '" + state.name + "'"
        ].join(' '));
    };

    self.create = function(name, opts) {
        /**:AppStates.create(name, opts)

        Creates the given state represented by the given state name by
        delegating to the associated state creator.

        :param string name:
            the name of the state to create.
        :param object opts:
            Options for the state creator to use. Optional.

        If no creator is found for the requested state name, we create a start
        state instead.

        This function returns a promise.

        It may be overridden by :class:`AppStates` subclasses that wish
        to provide a completely dynamic set of states.
        */
        var creator;
        opts = opts || {};

        if (name == self.app.start_state_name) {
            creator = self.creators.__start__;
        }
        else if (name in self.creators) {
            creator = self.creators[name];
        }
        else {
            self.im.log(
                "Unknown state '" + name + "'. Switching to" +
                " start state '" + self.app.start_state_name + "'.");

            creator = self.creators.__start__;
            name = self.app.start_state_name;
        }

        return Q(creator.call(self.app, name, opts))
            .then(function(state) {
                self.check(state, name);
                return state;
            })
            .catch(function(e) {
                self.im.log(e.message);
                return self.create('__error__');
            });
    };

    self.creators.__error__ = function(name) {
        /**:AppStates.creators.__error__(name)

        Creates the fallback error state.

        :param string name:
            the name of the state for which an error occurred.

        This default implementation creates an EndState with name
        ``name`` and content *"An error occurred. Please try again later"*.

        The end state created has the next state set to ``null``. When the
        state receives input, it will invoke :meth:`UserStateData.change` to
        change the user's current state. Since the state given to it is
        ``null``, it will instead stay on the current state.

        If we are dealing with a new user, then the :class:`InteractionMachine`
        will have requested the start state to have been created. If the start
        state does not exist, we will end up here again, ensuring the same
        message will be displayed.
        */
        return new EndState(name, {
            next: null,
            text: "An error occurred. Please try again later."
        });
    };

    self.creators.__start__ = function(name) {
        /**:AppStates.creators.__start__(name)

        :param string name:
            the name of the start state.
        :param InteractionMachine im:
            the interaction machine the start state is for.

        The default implemenation looks up a creator for the state named
        ``name`` and calls that. If no such creator exists, it uses
        :meth:`App.creators.__error__` instead.
        */
        var creator = self.creators[name];

        if (!creator) {
            self.im.log([
                "Unknown start state '" + name + "'.",
                "Switching to error state."].join(' '));

            creator = self.creators.__error__;
            name = '__error__';
        }

        return creator.call(self.app, name);
    };
});

this.App = App;
this.AppStates = AppStates;
<|endoftext|>


<commit_before>/*
   _            _     __
  | |_ __ _ ___| | __/ _| ___  _ __ ___ ___
  | __/ _` / __| |/ / |_ / _ \| '__/ __/ _ \
  | || (_| \__ \   <|  _| (_) | | | (_|  __/
   \__\__,_|___/_|\_\_|  \___/|_|  \___\___|

  ===============================================================================

  A generic widget include script which we will use to show further campaigns etc

  <thomasalwyndavis@gmail.com> or http://taskforce.is for support

  ===============================================================================

  TODO
    - Use underscores or camelcase?

*/

// Wrap widget in function to protect scope
var _tfrce_config = (typeof tfrce_config  !== 'undefined') ? tfrce_config  : {};

(function(window, widget_config){

  // Do configuration

  widget_config.show_style = widget_config.show_style || 'center_modal';
  widget_config.disableGeo = widget_config.disableGeo || false;
  widget_config.debug = widget_config.debug || false;
  widget_config.disableDate = widget_config.disableDate || false;
  widget_config.campaign = widget_config.campaign || 'stopwatchingus';
  widget_config.cookieTimeout = widget_config.cookieTimeout || 172800;

  // Setup
  var active_campaign;
  var ASSET_URL, COOKIE_TIMEOUT;

  if(widget_config.debug) {
    ASSET_URL = '../stopwatchingus/';
    COOKIE_TIMEOUT = 20;
  } else {
    ASSET_URL = '//widget.taskforce.is/widget/stopwatchingus/';
    COOKIE_TIMEOUT = widget_config.cookieTimeout;
  }

  // Cookie helpers, taken from w3schools
  function setCookie(c_name,value,seconds) {
    var exdate = new Date(new Date().getTime() + seconds*1000);
    var c_value=escape(value) + ((seconds==null) ? "" : "; expires="+exdate.toUTCString());
    document.cookie=c_name + "=" + c_value;
  }

  function getCookie(c_name) {
    var c_value = document.cookie;
    var c_start = c_value.indexOf(" " + c_name + "=");
    if (c_start == -1) { c_start = c_value.indexOf(c_name + "="); };
    if (c_start == -1) {
      c_value = null;
    } else {
      c_start = c_value.indexOf("=", c_start) + 1;
      var c_end = c_value.indexOf(";", c_start);
      if (c_end == -1) { c_end = c_value.length; }
      c_value = unescape(c_value.substring(c_start,c_end));
    }
    return c_value;
  }

  // Define checks

  var checks = {
    betweenDate: function(startDate, endDate) {
      var startEpoch = startDate.getTime();
      var endEpoch = endDate.getTime();
      var currentEpoch = new Date().getTime();
      if(currentEpoch > startEpoch && currentEpoch < endEpoch) {
        return true;
      } else {
        return false;
      }
    },
    isMobile: function() {
      var ismobile = navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i);
      return ismobile ? false : true;
    },
    hasSeenCampaign: function (cookieName) {
      var cookie = getCookie(cookieName)
      if(cookie === null) {
        return false;
      } else {
        return true
      }
    },
    nearDC: function (callback) {
      window.nearDC = callback;
      var script = document.createElement('script');
      script.src = '//geoip.taskforce.is/?callback=nearDC'
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  }

  // Define campaigns

  var campaign = {
    stopwatchingus: {
      cookieName: 'stopwatchingus_hasseen6',
      startDate: new Date(2013, 10, 15, 0),
      endDate: new Date(2013, 10, 26, 12),
      hide: function (el, callback) {
        document.body.removeChild(el);
        setCookie(active_campaign.cookieName, 'true', COOKIE_TIMEOUT);
        if(callback) { callback(); };
      },
      styles: {
        modal: {
          campaign_container: '',
          iframe_container: '',
          iframe: '',
          closeButton: ''
        },
        banner: {
          campaign_container: 'position:fixed;width:100%;bottom:0;z-index:100; padding: 0 20px;',
          iframe_container: 'position: relative; height: 100px; max-width:1201px; margin: 0px auto 8px auto; background: #444;border-radius: 10px;',
          iframe: 'width: 100%;height: 100%;border: 0;margin:0;padding:0;border-radius: 10px;',
          closeButton: 'border: 0;height: 28px;width: 28px;cursor: pointer;position: absolute;top:33px;right:20px;background: url("' + ASSET_URL +'images/close-button.png");'
        },
        dev: {
          campaign_container: 'position:fixed;width:100%;bottom:0;z-index:100; padding: 0 20px;',
          iframe_container: 'position: relative; height: 100px; max-width:1201px; margin: 0px auto 8px auto; background: #444;border-radius: 10px;',
          iframe: 'width: 100%;height: 100%;border: 0;margin:0;padding:0;border-radius: 10px;',
          closeButton: 'border: 0;height: 28px;width: 28px;cursor: pointer;position: absolute;top:33px;right:20px;background: url("' + ASSET_URL +'images/close-button.png");'
        },
        strip: {
          campaign_container: 'position:fixed;width:100%;bottom:0;opacity:1;z-index:100;',
          iframe_container: 'position:relative;height:50px;margin:0 20px 0px 20px;background:#444;border-radius:10px 10px 0 0;',
          iframe: 'width:100%;height:100%;border:0;margin:0;padding:0;border-radius:10px;',
          closeButton: 'border:0;height:28px;width:28px;cursor:pointer;position:absolute;top:11px;right:10px;background:url("' + ASSET_URL +'images/close-button.png");'
        },
        modal: {
          overlay: 'position:fixed; background:#000; width:100%; height:100%;z-index:30;top:0; left:0; opacity:0.5;-moz-opacity: 0.50;filter: alpha(opacity=50);',
          campaign_container: 'position:fixed;left:50%;margin-left:-250px;margin-top:40px;width:500px;top:0;opacity:1;z-index:100;',
          iframe_container: 'position:relative;height:365px; width:500px;background:#444;border-radius:10px;',
          iframe: 'width:100%;height:100%;border:0;margin:0;padding:0;border-radius:10px;',
          closeButton: 'border:0;height:28px;width:28px;cursor:pointer;position:absolute;top:15px;right:15px;background:url("' + ASSET_URL +'images/close-button.png");'
        }
      },
      show: function () {

        var style = active_campaign.styles[active_campaign.config.show_style]

        if(style.overlay) {
          var overlay = document.createElement('div');
          overlay.style.cssText = style.overlay;
          document.body.appendChild(overlay);
        }

        // Create a container
        var campaign_container = document.createElement('div');
        campaign_container.style.cssText = style.campaign_container;

        // Create a container for the iframe so we can do padding and border-radius properly
        var iframe_container = document.createElement('div');
        iframe_container.style.cssText = style.iframe_container;

        // Append Iframe and campaign container to document
        campaign_container.appendChild(iframe_container);
        document.body.appendChild(campaign_container);

        var iframe = document.createElement('iframe');
        iframe.style.cssText = style.iframe;

        // Set the source of the iframe to the configured show_style type
        iframe.src = ASSET_URL + active_campaign.config.show_style + '.html';
        iframe_container.appendChild(iframe);

        // Setup a close button
        var closeButton = document.createElement('button');
        closeButton.style.cssText = style.closeButton;
        iframe_container.appendChild(closeButton);
        closeButton.onclick = function() {
          active_campaign.hide(campaign_container);
          if(style.overlay) {
            document.body.removeChild(overlay);
          }
        }

      },
      init: function (config) {
        active_campaign.config = config;
        // Check cookie for this campaign
        if(checks.hasSeenCampaign(active_campaign.cookieName)) {
          return false;
        }

        // Check between date
        if(!checks.betweenDate(active_campaign.startDate, active_campaign.endDate) || active_campaign.config.disableDate) {
          return false;
        }

        // Check if is mobile
        if(!checks.isMobile()){
          return false;
        }

        // Check if they are near Washington?
        if(active_campaign.config.disableGeo) {
          active_campaign.show();
        } else {
          checks.nearDC(function (res) {
            if(res.kilometersFromDC <= 700) {
              active_campaign.show();
            }
          })
        }
      }
    }
  }

  // Load campaign if exist

  if(typeof campaign[widget_config.campaign] !== 'undefined') {
    active_campaign = campaign[widget_config.campaign];
    active_campaign.init(widget_config);
  } else {
    return false;
  }

})(window, _tfrce_config);
<commit_msg>Changed date back a day<commit_after>/*
   _            _     __
  | |_ __ _ ___| | __/ _| ___  _ __ ___ ___
  | __/ _` / __| |/ / |_ / _ \| '__/ __/ _ \
  | || (_| \__ \   <|  _| (_) | | | (_|  __/
   \__\__,_|___/_|\_\_|  \___/|_|  \___\___|

  ===============================================================================

  A generic widget include script which we will use to show further campaigns etc

  <thomasalwyndavis@gmail.com> or http://taskforce.is for support

  ===============================================================================

  TODO
    - Use underscores or camelcase?

*/

// Wrap widget in function to protect scope
var _tfrce_config = (typeof tfrce_config  !== 'undefined') ? tfrce_config  : {};

(function(window, widget_config){

  // Do configuration

  widget_config.show_style = widget_config.show_style || 'center_modal';
  widget_config.disableGeo = widget_config.disableGeo || false;
  widget_config.debug = widget_config.debug || false;
  widget_config.disableDate = widget_config.disableDate || false;
  widget_config.campaign = widget_config.campaign || 'stopwatchingus';
  widget_config.cookieTimeout = widget_config.cookieTimeout || 172800;

  // Setup
  var active_campaign;
  var ASSET_URL, COOKIE_TIMEOUT;

  if(widget_config.debug) {
    ASSET_URL = '../stopwatchingus/';
    COOKIE_TIMEOUT = 20;
  } else {
    ASSET_URL = '//widget.taskforce.is/widget/stopwatchingus/';
    COOKIE_TIMEOUT = widget_config.cookieTimeout;
  }

  // Cookie helpers, taken from w3schools
  function setCookie(c_name,value,seconds) {
    var exdate = new Date(new Date().getTime() + seconds*1000);
    var c_value=escape(value) + ((seconds==null) ? "" : "; expires="+exdate.toUTCString());
    document.cookie=c_name + "=" + c_value;
  }

  function getCookie(c_name) {
    var c_value = document.cookie;
    var c_start = c_value.indexOf(" " + c_name + "=");
    if (c_start == -1) { c_start = c_value.indexOf(c_name + "="); };
    if (c_start == -1) {
      c_value = null;
    } else {
      c_start = c_value.indexOf("=", c_start) + 1;
      var c_end = c_value.indexOf(";", c_start);
      if (c_end == -1) { c_end = c_value.length; }
      c_value = unescape(c_value.substring(c_start,c_end));
    }
    return c_value;
  }

  // Define checks

  var checks = {
    betweenDate: function(startDate, endDate) {
      var startEpoch = startDate.getTime();
      var endEpoch = endDate.getTime();
      var currentEpoch = new Date().getTime();
      if(currentEpoch > startEpoch && currentEpoch < endEpoch) {
        return true;
      } else {
        return false;
      }
    },
    isMobile: function() {
      var ismobile = navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i);
      return ismobile ? false : true;
    },
    hasSeenCampaign: function (cookieName) {
      var cookie = getCookie(cookieName)
      if(cookie === null) {
        return false;
      } else {
        return true
      }
    },
    nearDC: function (callback) {
      window.nearDC = callback;
      var script = document.createElement('script');
      script.src = '//geoip.taskforce.is/?callback=nearDC'
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  }

  // Define campaigns

  var campaign = {
    stopwatchingus: {
      cookieName: 'stopwatchingus_hasseen6',
      startDate: new Date(2013, 10, 14, 0),
      endDate: new Date(2013, 10, 26, 12),
      hide: function (el, callback) {
        document.body.removeChild(el);
        setCookie(active_campaign.cookieName, 'true', COOKIE_TIMEOUT);
        if(callback) { callback(); };
      },
      styles: {
        modal: {
          campaign_container: '',
          iframe_container: '',
          iframe: '',
          closeButton: ''
        },
        banner: {
          campaign_container: 'position:fixed;width:100%;bottom:0;z-index:100; padding: 0 20px;',
          iframe_container: 'position: relative; height: 100px; max-width:1201px; margin: 0px auto 8px auto; background: #444;border-radius: 10px;',
          iframe: 'width: 100%;height: 100%;border: 0;margin:0;padding:0;border-radius: 10px;',
          closeButton: 'border: 0;height: 28px;width: 28px;cursor: pointer;position: absolute;top:33px;right:20px;background: url("' + ASSET_URL +'images/close-button.png");'
        },
        dev: {
          campaign_container: 'position:fixed;width:100%;bottom:0;z-index:100; padding: 0 20px;',
          iframe_container: 'position: relative; height: 100px; max-width:1201px; margin: 0px auto 8px auto; background: #444;border-radius: 10px;',
          iframe: 'width: 100%;height: 100%;border: 0;margin:0;padding:0;border-radius: 10px;',
          closeButton: 'border: 0;height: 28px;width: 28px;cursor: pointer;position: absolute;top:33px;right:20px;background: url("' + ASSET_URL +'images/close-button.png");'
        },
        strip: {
          campaign_container: 'position:fixed;width:100%;bottom:0;opacity:1;z-index:100;',
          iframe_container: 'position:relative;height:50px;margin:0 20px 0px 20px;background:#444;border-radius:10px 10px 0 0;',
          iframe: 'width:100%;height:100%;border:0;margin:0;padding:0;border-radius:10px;',
          closeButton: 'border:0;height:28px;width:28px;cursor:pointer;position:absolute;top:11px;right:10px;background:url("' + ASSET_URL +'images/close-button.png");'
        },
        modal: {
          overlay: 'position:fixed; background:#000; width:100%; height:100%;z-index:30;top:0; left:0; opacity:0.5;-moz-opacity: 0.50;filter: alpha(opacity=50);',
          campaign_container: 'position:fixed;left:50%;margin-left:-250px;margin-top:40px;width:500px;top:0;opacity:1;z-index:100;',
          iframe_container: 'position:relative;height:365px; width:500px;background:#444;border-radius:10px;',
          iframe: 'width:100%;height:100%;border:0;margin:0;padding:0;border-radius:10px;',
          closeButton: 'border:0;height:28px;width:28px;cursor:pointer;position:absolute;top:15px;right:15px;background:url("' + ASSET_URL +'images/close-button.png");'
        }
      },
      show: function () {

        var style = active_campaign.styles[active_campaign.config.show_style]

        if(style.overlay) {
          var overlay = document.createElement('div');
          overlay.style.cssText = style.overlay;
          document.body.appendChild(overlay);
        }

        // Create a container
        var campaign_container = document.createElement('div');
        campaign_container.style.cssText = style.campaign_container;

        // Create a container for the iframe so we can do padding and border-radius properly
        var iframe_container = document.createElement('div');
        iframe_container.style.cssText = style.iframe_container;

        // Append Iframe and campaign container to document
        campaign_container.appendChild(iframe_container);
        document.body.appendChild(campaign_container);

        var iframe = document.createElement('iframe');
        iframe.style.cssText = style.iframe;

        // Set the source of the iframe to the configured show_style type
        iframe.src = ASSET_URL + active_campaign.config.show_style + '.html';
        iframe_container.appendChild(iframe);

        // Setup a close button
        var closeButton = document.createElement('button');
        closeButton.style.cssText = style.closeButton;
        iframe_container.appendChild(closeButton);
        closeButton.onclick = function() {
          active_campaign.hide(campaign_container);
          if(style.overlay) {
            document.body.removeChild(overlay);
          }
        }

      },
      init: function (config) {
        active_campaign.config = config;
        // Check cookie for this campaign
        if(checks.hasSeenCampaign(active_campaign.cookieName)) {
          return false;
        }

        // Check between date
        if(!checks.betweenDate(active_campaign.startDate, active_campaign.endDate) || active_campaign.config.disableDate) {
          return false;
        }

        // Check if is mobile
        if(!checks.isMobile()){
          return false;
        }

        // Check if they are near Washington?
        if(active_campaign.config.disableGeo) {
          active_campaign.show();
        } else {
          checks.nearDC(function (res) {
            if(res.kilometersFromDC <= 700) {
              active_campaign.show();
            }
          })
        }
      }
    }
  }

  // Load campaign if exist

  if(typeof campaign[widget_config.campaign] !== 'undefined') {
    active_campaign = campaign[widget_config.campaign];
    active_campaign.init(widget_config);
  } else {
    return false;
  }

})(window, _tfrce_config);
<|endoftext|>


<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.
*/

var fs            = require('fs'),
    path          = require('path'),
    et            = require('elementtree'),
    xml           = require('cordova-common').xmlHelpers,
    util          = require('../util'),
    events        = require('cordova-common').events,
    shell         = require('shelljs'),
    Q             = require('q'),
    Parser        = require('./parser'),
    ConfigParser = require('cordova-common').ConfigParser,
    CordovaError = require('cordova-common').CordovaError;

function android_parser(project) {
    if (!fs.existsSync(path.join(project, 'AndroidManifest.xml'))) {
        throw new CordovaError('The provided path "' + project + '" is not an Android project.');
    }

    // Call the base class constructor
    Parser.call(this, 'android', project);

    this.path = project;
    this.strings = path.join(this.path, 'res', 'values', 'strings.xml');
    this.manifest = path.join(this.path, 'AndroidManifest.xml');
    this.android_config = path.join(this.path, 'res', 'xml', 'config.xml');
}

require('util').inherits(android_parser, Parser);

module.exports = android_parser;

android_parser.prototype.findAndroidLaunchModePreference = function(config) {
    var launchMode = config.getPreference('AndroidLaunchMode');
    if (!launchMode) {
        // Return a default value
        return 'singleTop';
    }

    var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
    var valid = expectedValues.indexOf(launchMode) !== -1;
    if (!valid) {
        events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' + launchMode);
        events.emit('warn', '  Expected values are: ' + expectedValues.join(', '));
        // Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
    }

    return launchMode;
};

// remove the default resource name from all drawable folders
// return the array of the densities in this project
android_parser.prototype.deleteDefaultResource = function(name) {
    var res = path.join(this.path, 'res');
    var dirs = fs.readdirSync(res);

    for (var i=0; i<dirs.length; i++) {
        var filename = dirs[i];
        if (filename.indexOf('drawable-') === 0) {
            var imgPath = path.join(res, filename, name);
            if (fs.existsSync(imgPath)) {
                fs.unlinkSync(imgPath);
                events.emit('verbose', 'deleted: ' + imgPath);
            }
            imgPath = imgPath.replace(/\.png$/, '.9.png');
            if (fs.existsSync(imgPath)) {
                fs.unlinkSync(imgPath);
                events.emit('verbose', 'deleted: ' + imgPath);
            }
        }
    }
};

android_parser.prototype.copyImage = function(src, density, name) {
    var destFolder = path.join(this.path, 'res', (density ? 'drawable-': 'drawable') + density);
    var isNinePatch = !!/\.9\.png$/.exec(src);
    var ninePatchName = name.replace(/\.png$/, '.9.png');

    // default template does not have default asset for this density
    if (!fs.existsSync(destFolder)) {
        fs.mkdirSync(destFolder);
    }

    var destFilePath = path.join(destFolder, isNinePatch ? ninePatchName : name);
    events.emit('verbose', 'copying image from ' + src + ' to ' + destFilePath);
    shell.cp('-f', src, destFilePath);
};

android_parser.prototype.handleSplashes = function(config) {
    var resources = config.getSplashScreens('android');
    var me = this;
    // if there are "splash" elements in config.xml
    if (resources.length > 0) {
        this.deleteDefaultResource('screen.png');
        events.emit('verbose', 'splash screens: ' + JSON.stringify(resources));

        var projectRoot = util.isCordova(this.path);

        var hadMdpi = false;
        resources.forEach(function (resource) {
            if (!resource.density) {
                return;
            }
            if (resource.density == 'mdpi') {
                hadMdpi = true;
            }
            me.copyImage(path.join(projectRoot, resource.src), resource.density, 'screen.png');
        });
        // There's no "default" drawable, so assume default == mdpi.
        if (!hadMdpi && resources.defaultResource) {
            me.copyImage(path.join(projectRoot, resources.defaultResource.src), 'mdpi', 'screen.png');
        }
    }
};

android_parser.prototype.handleIcons = function(config) {
    var icons = config.getIcons('android');

    // if there are icon elements in config.xml
    if (icons.length === 0) {
        events.emit('verbose', 'This app does not have launcher icons defined');
        return;
    }

    this.deleteDefaultResource('icon.png');

    var android_icons = {};
    var default_icon;
    // http://developer.android.com/design/style/iconography.html
    var sizeToDensityMap = {
        36: 'ldpi',
        48: 'mdpi',
        72: 'hdpi',
        96: 'xhdpi',
        144: 'xxhdpi',
        192: 'xxxhdpi'
    };
    // find the best matching icon for a given density or size
    // @output android_icons
    var parseIcon = function(icon, icon_size) {
        // do I have a platform icon for that density already
        var density = icon.density || sizeToDensityMap[icon_size];
        if (!density) {
            // invalid icon defition ( or unsupported size)
            return;
        }
        var previous = android_icons[density];
        if (previous && previous.platform) {
            return;
        }
        android_icons[density] = icon;
    };

    // iterate over all icon elements to find the default icon and call parseIcon
    for (var i=0; i<icons.length; i++) {
        var icon = icons[i];
        var size = icon.width;
        if (!size) {
            size = icon.height;
        }
        if (!size && !icon.density) {
            if (default_icon) {
                events.emit('verbose', 'more than one default icon: ' + JSON.stringify(icon));
            } else {
                default_icon = icon;
            }
        } else {
            parseIcon(icon, size);
        }
    }
    var projectRoot = util.isCordova(this.path);
    for (var density in android_icons) {
        this.copyImage(path.join(projectRoot, android_icons[density].src), density, 'icon.png');
    }
    // There's no "default" drawable, so assume default == mdpi.
    if (default_icon && !android_icons.mdpi) {
        this.copyImage(path.join(projectRoot, default_icon.src), 'mdpi', 'icon.png');
    }
};

android_parser.prototype.update_from_config = function(config) {
    // TODO: share code for this func with Android. Or fix it and remove
    // the below JSHint hacks line.
    // jshint unused:false, indent:false, undef:true, loopfunc:true, shadow:true, quotmark:false
    if (config instanceof ConfigParser) {
    } else throw new Error('update_from_config requires a ConfigParser object');

    // Update app name by editing res/values/strings.xml
    var name = config.name();
    var strings = xml.parseElementtreeSync(this.strings);
    strings.find('string[@name="app_name"]').text = name;
    fs.writeFileSync(this.strings, strings.write({indent: 4}), 'utf-8');
    events.emit('verbose', 'Wrote out Android application name to "' + name + '"');

    this.handleSplashes(config);
    this.handleIcons(config);

    var manifest = xml.parseElementtreeSync(this.manifest);
    // Update the version by changing the AndroidManifest android:versionName
    var version = config.version();
    var versionCode = config.android_versionCode() || default_versionCode(version);
    manifest.getroot().attrib["android:versionName"] = version;
    manifest.getroot().attrib["android:versionCode"] = versionCode;

    // Update package name by changing the AndroidManifest id and moving the entry class around to the proper package directory
    var pkg = config.android_packageName() || config.packageName();
    pkg = pkg.replace(/-/g, '_'); // Java packages cannot support dashes
    var orig_pkg = manifest.getroot().attrib.package;
    manifest.getroot().attrib.package = pkg;

    var act = manifest.getroot().find('./application/activity');

    // Set the android:screenOrientation in the AndroidManifest
    var orientation = this.helper.getOrientation(config);

    if (orientation && !this.helper.isDefaultOrientation(orientation)) {
        act.attrib['android:screenOrientation'] = orientation;
    } else {
        delete act.attrib['android:screenOrientation'];
    }

    // Set android:launchMode in AndroidManifest
    var androidLaunchModePref = this.findAndroidLaunchModePreference(config);
    if (androidLaunchModePref) {
        act.attrib["android:launchMode"] = androidLaunchModePref;
    } else { // User has (explicitly) set an invalid value for AndroidLaunchMode preference
        delete act.attrib["android:launchMode"]; // use Android default value (standard)
    }

    // Set min/max/target SDK version
    //<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" ... />
    var usesSdk = manifest.getroot().find('./uses-sdk');
    ['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion'].forEach(function(sdkPrefName) {
        var sdkPrefValue = config.getPreference('android-' + sdkPrefName, 'android');
        if (!sdkPrefValue) return;

        if (!usesSdk) { // if there is no required uses-sdk element, we should create it first
            usesSdk = new et.Element('uses-sdk');
            manifest.getroot().append(usesSdk);
        }
        usesSdk.attrib['android:' + sdkPrefName] = sdkPrefValue;
    });

    // Write out AndroidManifest.xml
    fs.writeFileSync(this.manifest, manifest.write({indent: 4}), 'utf-8');

    var orig_pkgDir = path.join(this.path, 'src', path.join.apply(null, orig_pkg.split('.')));
    var java_files = fs.readdirSync(orig_pkgDir).filter(function(f) {
      return f.indexOf('.svn') == -1 && f.indexOf('.java') >= 0 && fs.readFileSync(path.join(orig_pkgDir, f), 'utf-8').match(/extends\s+CordovaActivity/);
    });
    if (java_files.length === 0) {
      throw new Error('No Java files found which extend CordovaActivity.');
    } else if(java_files.length > 1) {
      events.emit('log', 'Multiple candidate Java files (.java files which extend CordovaActivity) found. Guessing at the first one, ' + java_files[0]);
    }

    var orig_java_class = java_files[0];
    var pkgDir = path.join(this.path, 'src', path.join.apply(null, pkg.split('.')));
    shell.mkdir('-p', pkgDir);
    var orig_javs = path.join(orig_pkgDir, orig_java_class);
    var new_javs = path.join(pkgDir, orig_java_class);
    var javs_contents = fs.readFileSync(orig_javs, 'utf-8');
    javs_contents = javs_contents.replace(/package [\w\.]*;/, 'package ' + pkg + ';');
    events.emit('verbose', 'Wrote out Android package name to "' + pkg + '"');
    fs.writeFileSync(new_javs, javs_contents, 'utf-8');
};

// Returns the platform-specific www directory.
android_parser.prototype.www_dir = function() {
    return path.join(this.path, 'assets', 'www');
};

android_parser.prototype.config_xml = function(){
    return this.android_config;
};

// Used for creating platform_www in projects created by older versions.
android_parser.prototype.cordovajs_path = function(libDir) {
    var jsPath = path.join(libDir, 'framework', 'assets', 'www', 'cordova.js');
    return path.resolve(jsPath);
};

android_parser.prototype.cordovajs_src_path = function(libDir) {
    var jsPath = path.join(libDir, 'cordova-js-src');
    return path.resolve(jsPath);
};

// Replace the www dir with contents of platform_www and app www.
android_parser.prototype.update_www = function() {
    var projectRoot = util.isCordova(this.path);
    var app_www = util.projectWww(projectRoot);
    var platform_www = path.join(this.path, 'platform_www');

    // Clear the www dir
    shell.rm('-rf', this.www_dir());
    shell.mkdir(this.www_dir());
    // Copy over all app www assets
    shell.cp('-rf', path.join(app_www, '*'), this.www_dir());
    // Copy over stock platform www assets (cordova.js)
    shell.cp('-rf', path.join(platform_www, '*'), this.www_dir());
};

// update the overrides folder into the www folder
android_parser.prototype.update_overrides = function() {
    var projectRoot = util.isCordova(this.path);
    var merges_path = path.join(util.appDir(projectRoot), 'merges', 'android');
    if (fs.existsSync(merges_path)) {
        var overrides = path.join(merges_path, '*');
        shell.cp('-rf', overrides, this.www_dir());
    }
};

// Returns a promise.
android_parser.prototype.update_project = function(cfg) {
    var platformWww = path.join(this.path, 'assets');
    try {
        this.update_from_config(cfg);
        this.update_overrides();
    } catch(e) {
        return Q.reject(e);
    }
    // delete any .svn folders copied over
    util.deleteSvnFolders(platformWww);
    return Q();
};

// Consturct the default value for versionCode as
// PATCH + MINOR * 100 + MAJOR * 10000
// see http://developer.android.com/tools/publishing/versioning.html
function default_versionCode(version) {
    var nums = version.split('-')[0].split('.');
    var versionCode = 0;
    if (+nums[0]) {
        versionCode += +nums[0] * 10000;
    }
    if (+nums[1]) {
        versionCode += +nums[1] * 100;
    }
    if (+nums[2]) {
        versionCode += +nums[2];
    }
    return versionCode;
}
<commit_msg>CB-9736 - Extra main activity generated when an android package name is specified<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.
*/

var fs            = require('fs'),
    path          = require('path'),
    et            = require('elementtree'),
    xml           = require('cordova-common').xmlHelpers,
    util          = require('../util'),
    events        = require('cordova-common').events,
    shell         = require('shelljs'),
    Q             = require('q'),
    Parser        = require('./parser'),
    ConfigParser = require('cordova-common').ConfigParser,
    CordovaError = require('cordova-common').CordovaError;

function android_parser(project) {
    if (!fs.existsSync(path.join(project, 'AndroidManifest.xml'))) {
        throw new CordovaError('The provided path "' + project + '" is not an Android project.');
    }

    // Call the base class constructor
    Parser.call(this, 'android', project);

    this.path = project;
    this.strings = path.join(this.path, 'res', 'values', 'strings.xml');
    this.manifest = path.join(this.path, 'AndroidManifest.xml');
    this.android_config = path.join(this.path, 'res', 'xml', 'config.xml');
}

require('util').inherits(android_parser, Parser);

module.exports = android_parser;

android_parser.prototype.findAndroidLaunchModePreference = function(config) {
    var launchMode = config.getPreference('AndroidLaunchMode');
    if (!launchMode) {
        // Return a default value
        return 'singleTop';
    }

    var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
    var valid = expectedValues.indexOf(launchMode) !== -1;
    if (!valid) {
        events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' + launchMode);
        events.emit('warn', '  Expected values are: ' + expectedValues.join(', '));
        // Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
    }

    return launchMode;
};

// remove the default resource name from all drawable folders
// return the array of the densities in this project
android_parser.prototype.deleteDefaultResource = function(name) {
    var res = path.join(this.path, 'res');
    var dirs = fs.readdirSync(res);

    for (var i=0; i<dirs.length; i++) {
        var filename = dirs[i];
        if (filename.indexOf('drawable-') === 0) {
            var imgPath = path.join(res, filename, name);
            if (fs.existsSync(imgPath)) {
                fs.unlinkSync(imgPath);
                events.emit('verbose', 'deleted: ' + imgPath);
            }
            imgPath = imgPath.replace(/\.png$/, '.9.png');
            if (fs.existsSync(imgPath)) {
                fs.unlinkSync(imgPath);
                events.emit('verbose', 'deleted: ' + imgPath);
            }
        }
    }
};

android_parser.prototype.copyImage = function(src, density, name) {
    var destFolder = path.join(this.path, 'res', (density ? 'drawable-': 'drawable') + density);
    var isNinePatch = !!/\.9\.png$/.exec(src);
    var ninePatchName = name.replace(/\.png$/, '.9.png');

    // default template does not have default asset for this density
    if (!fs.existsSync(destFolder)) {
        fs.mkdirSync(destFolder);
    }

    var destFilePath = path.join(destFolder, isNinePatch ? ninePatchName : name);
    events.emit('verbose', 'copying image from ' + src + ' to ' + destFilePath);
    shell.cp('-f', src, destFilePath);
};

android_parser.prototype.handleSplashes = function(config) {
    var resources = config.getSplashScreens('android');
    var me = this;
    // if there are "splash" elements in config.xml
    if (resources.length > 0) {
        this.deleteDefaultResource('screen.png');
        events.emit('verbose', 'splash screens: ' + JSON.stringify(resources));

        var projectRoot = util.isCordova(this.path);

        var hadMdpi = false;
        resources.forEach(function (resource) {
            if (!resource.density) {
                return;
            }
            if (resource.density == 'mdpi') {
                hadMdpi = true;
            }
            me.copyImage(path.join(projectRoot, resource.src), resource.density, 'screen.png');
        });
        // There's no "default" drawable, so assume default == mdpi.
        if (!hadMdpi && resources.defaultResource) {
            me.copyImage(path.join(projectRoot, resources.defaultResource.src), 'mdpi', 'screen.png');
        }
    }
};

android_parser.prototype.handleIcons = function(config) {
    var icons = config.getIcons('android');

    // if there are icon elements in config.xml
    if (icons.length === 0) {
        events.emit('verbose', 'This app does not have launcher icons defined');
        return;
    }

    this.deleteDefaultResource('icon.png');

    var android_icons = {};
    var default_icon;
    // http://developer.android.com/design/style/iconography.html
    var sizeToDensityMap = {
        36: 'ldpi',
        48: 'mdpi',
        72: 'hdpi',
        96: 'xhdpi',
        144: 'xxhdpi',
        192: 'xxxhdpi'
    };
    // find the best matching icon for a given density or size
    // @output android_icons
    var parseIcon = function(icon, icon_size) {
        // do I have a platform icon for that density already
        var density = icon.density || sizeToDensityMap[icon_size];
        if (!density) {
            // invalid icon defition ( or unsupported size)
            return;
        }
        var previous = android_icons[density];
        if (previous && previous.platform) {
            return;
        }
        android_icons[density] = icon;
    };

    // iterate over all icon elements to find the default icon and call parseIcon
    for (var i=0; i<icons.length; i++) {
        var icon = icons[i];
        var size = icon.width;
        if (!size) {
            size = icon.height;
        }
        if (!size && !icon.density) {
            if (default_icon) {
                events.emit('verbose', 'more than one default icon: ' + JSON.stringify(icon));
            } else {
                default_icon = icon;
            }
        } else {
            parseIcon(icon, size);
        }
    }
    var projectRoot = util.isCordova(this.path);
    for (var density in android_icons) {
        this.copyImage(path.join(projectRoot, android_icons[density].src), density, 'icon.png');
    }
    // There's no "default" drawable, so assume default == mdpi.
    if (default_icon && !android_icons.mdpi) {
        this.copyImage(path.join(projectRoot, default_icon.src), 'mdpi', 'icon.png');
    }
};

android_parser.prototype.update_from_config = function(config) {
    // TODO: share code for this func with Android. Or fix it and remove
    // the below JSHint hacks line.
    // jshint unused:false, indent:false, undef:true, loopfunc:true, shadow:true, quotmark:false
    if (config instanceof ConfigParser) {
    } else throw new Error('update_from_config requires a ConfigParser object');

    // Update app name by editing res/values/strings.xml
    var name = config.name();
    var strings = xml.parseElementtreeSync(this.strings);
    strings.find('string[@name="app_name"]').text = name;
    fs.writeFileSync(this.strings, strings.write({indent: 4}), 'utf-8');
    events.emit('verbose', 'Wrote out Android application name to "' + name + '"');

    this.handleSplashes(config);
    this.handleIcons(config);

    var manifest = xml.parseElementtreeSync(this.manifest);
    // Update the version by changing the AndroidManifest android:versionName
    var version = config.version();
    var versionCode = config.android_versionCode() || default_versionCode(version);
    manifest.getroot().attrib["android:versionName"] = version;
    manifest.getroot().attrib["android:versionCode"] = versionCode;

    // Update package name by changing the AndroidManifest id and moving the entry class around to the proper package directory
    var pkg = config.android_packageName() || config.packageName();
    pkg = pkg.replace(/-/g, '_'); // Java packages cannot support dashes
    var orig_pkg = manifest.getroot().attrib.package;
    manifest.getroot().attrib.package = pkg;

    var act = manifest.getroot().find('./application/activity');

    // Set the android:screenOrientation in the AndroidManifest
    var orientation = this.helper.getOrientation(config);

    if (orientation && !this.helper.isDefaultOrientation(orientation)) {
        act.attrib['android:screenOrientation'] = orientation;
    } else {
        delete act.attrib['android:screenOrientation'];
    }

    // Set android:launchMode in AndroidManifest
    var androidLaunchModePref = this.findAndroidLaunchModePreference(config);
    if (androidLaunchModePref) {
        act.attrib["android:launchMode"] = androidLaunchModePref;
    } else { // User has (explicitly) set an invalid value for AndroidLaunchMode preference
        delete act.attrib["android:launchMode"]; // use Android default value (standard)
    }

    // Set min/max/target SDK version
    //<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" ... />
    var usesSdk = manifest.getroot().find('./uses-sdk');
    ['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion'].forEach(function(sdkPrefName) {
        var sdkPrefValue = config.getPreference('android-' + sdkPrefName, 'android');
        if (!sdkPrefValue) return;

        if (!usesSdk) { // if there is no required uses-sdk element, we should create it first
            usesSdk = new et.Element('uses-sdk');
            manifest.getroot().append(usesSdk);
        }
        usesSdk.attrib['android:' + sdkPrefName] = sdkPrefValue;
    });

    // Write out AndroidManifest.xml
    fs.writeFileSync(this.manifest, manifest.write({indent: 4}), 'utf-8');

    var orig_pkgDir = path.join(this.path, 'src', path.join.apply(null, orig_pkg.split('.')));
    var java_files = fs.readdirSync(orig_pkgDir).filter(function(f) {
      return f.indexOf('.svn') == -1 && f.indexOf('.java') >= 0 && fs.readFileSync(path.join(orig_pkgDir, f), 'utf-8').match(/extends\s+CordovaActivity/);
    });
    if (java_files.length === 0) {
      throw new Error('No Java files found which extend CordovaActivity.');
    } else if(java_files.length > 1) {
      events.emit('log', 'Multiple candidate Java files (.java files which extend CordovaActivity) found. Guessing at the first one, ' + java_files[0]);
    }

    var orig_java_class = java_files[0];
    var pkgDir = path.join(this.path, 'src', path.join.apply(null, pkg.split('.')));
    shell.mkdir('-p', pkgDir);
    var orig_javs = path.join(orig_pkgDir, orig_java_class);
    var new_javs = path.join(pkgDir, orig_java_class);
    var javs_contents = fs.readFileSync(orig_javs, 'utf-8');
    javs_contents = javs_contents.replace(/package [\w\.]*;/, 'package ' + pkg + ';');
    events.emit('verbose', 'Wrote out Android package name to "' + pkg + '"');
    fs.writeFileSync(new_javs, javs_contents, 'utf-8');
    // remove the original if different from the new.
    if(orig_pkgDir !== pkgDir){
      shell.rm('-Rf',orig_javs);
      // remove any empty directories
      var curDir = path.dirname(orig_javs);
      while(curDir !== path.resolve(this.path, 'src')) {
          if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
              fs.rmdirSync(curDir);
              curDir = path.resolve(curDir, '..');
            } else {
              break;
            }
          }
    }
};

// Returns the platform-specific www directory.
android_parser.prototype.www_dir = function() {
    return path.join(this.path, 'assets', 'www');
};

android_parser.prototype.config_xml = function(){
    return this.android_config;
};

// Used for creating platform_www in projects created by older versions.
android_parser.prototype.cordovajs_path = function(libDir) {
    var jsPath = path.join(libDir, 'framework', 'assets', 'www', 'cordova.js');
    return path.resolve(jsPath);
};

android_parser.prototype.cordovajs_src_path = function(libDir) {
    var jsPath = path.join(libDir, 'cordova-js-src');
    return path.resolve(jsPath);
};

// Replace the www dir with contents of platform_www and app www.
android_parser.prototype.update_www = function() {
    var projectRoot = util.isCordova(this.path);
    var app_www = util.projectWww(projectRoot);
    var platform_www = path.join(this.path, 'platform_www');

    // Clear the www dir
    shell.rm('-rf', this.www_dir());
    shell.mkdir(this.www_dir());
    // Copy over all app www assets
    shell.cp('-rf', path.join(app_www, '*'), this.www_dir());
    // Copy over stock platform www assets (cordova.js)
    shell.cp('-rf', path.join(platform_www, '*'), this.www_dir());
};

// update the overrides folder into the www folder
android_parser.prototype.update_overrides = function() {
    var projectRoot = util.isCordova(this.path);
    var merges_path = path.join(util.appDir(projectRoot), 'merges', 'android');
    if (fs.existsSync(merges_path)) {
        var overrides = path.join(merges_path, '*');
        shell.cp('-rf', overrides, this.www_dir());
    }
};

// Returns a promise.
android_parser.prototype.update_project = function(cfg) {
    var platformWww = path.join(this.path, 'assets');
    try {
        this.update_from_config(cfg);
        this.update_overrides();
    } catch(e) {
        return Q.reject(e);
    }
    // delete any .svn folders copied over
    util.deleteSvnFolders(platformWww);
    return Q();
};

// Consturct the default value for versionCode as
// PATCH + MINOR * 100 + MAJOR * 10000
// see http://developer.android.com/tools/publishing/versioning.html
function default_versionCode(version) {
    var nums = version.split('-')[0].split('.');
    var versionCode = 0;
    if (+nums[0]) {
        versionCode += +nums[0] * 10000;
    }
    if (+nums[1]) {
        versionCode += +nums[1] * 100;
    }
    if (+nums[2]) {
        versionCode += +nums[2];
    }
    return versionCode;
}
<|endoftext|>


<commit_before>/*
   Add a default clickhandler so we can use hrefs
 */
Backbone.View.prototype.defaultClickHandler = function( e ) {
  if ( e.metaKey || e.ctrlKey || e.altKey ) return;

  var routeTo = $(e.target).closest('a').attr('href');
  console.log("Navigating to "+ routeTo, 'from /'+ Backbone.history.fragment);

  if ('/' + Backbone.history.fragment == routeTo) {
    Backbone.history.fragment = null;
    Backbone.history.navigate(routeTo, {trigger: true, replace: true});
  } else {
    Backbone.history.navigate(routeTo, {trigger: true});
  }

  e.preventDefault();
  return false;
};

/* HACK: this is needed because internal events did not seem to work*/
$(":not(div.modal) a[rel=backbone]").live("click",Backbone.View.prototype.defaultClickHandler);
<commit_msg>Fix for using defaultClickHandler in pages that do not have Backbone.history initialized.<commit_after>/*
   Add a default clickhandler so we can use hrefs
 */
Backbone.View.prototype.defaultClickHandler = function( e ) {
  // Return if a modifier key is pressed or when Backbone has not properly been initialized
  // Make sure we return "true" so other functions can determine what happened
  // Note that the capitalization in Backbone.[H]istory is intentional
  if ( e.metaKey || e.ctrlKey || e.altKey || !Backbone.History.started ) return true;

  var routeTo = $(e.target).closest('a').attr('href');
  console.log("Navigating to "+ routeTo, 'from /'+ Backbone.history.fragment);

  if ('/' + Backbone.history.fragment == routeTo) {
    Backbone.history.fragment = null;
    Backbone.history.navigate(routeTo, {trigger: true, replace: true});
  } else {
    Backbone.history.navigate(routeTo, {trigger: true});
  }

  e.preventDefault();
  return false;
};

/* HACK: this is needed because internal events did not seem to work*/
$(":not(div.modal) a[rel=backbone]").live("click",Backbone.View.prototype.defaultClickHandler);
<|endoftext|>


<commit_before>angular.module('app.ctrl', ['ui.router', 'ngMaterial', 'app.service'])
// 首页
.controller('IndexCtrl',['$scope', '$http', 'KeyNames', '$mdDialog',
function($scope, $http, KeyNames, $mdDialog){
    // $http.get('www.baidu.com');
    var DialogController = function($scope, $http, $mdDialog) {
        $http.get(KeyNames.domain + '/oauth/req')
        .then(function(authLink){
            $scope.authLink = authLink.data.url;
            // window.open('http://wechat.qianmi.com/oauth/req');
        });
        $scope.hide = function() {
            $mdDialog.hide();
        };
        $scope.cancel = function() {
            $mdDialog.cancel();
        };
        $scope.answer = function(answer) {
            $mdDialog.hide(answer);
        };
    };
    $scope.fade = false;
    $scope.getOauth = function() {
        $http.get(KeyNames.domain + '/oauth/req')
        .then(function(authLink){
            $scope.authLink = authLink.data.url;
            // window.open('http://wechat.qianmi.com/oauth/req');
        });
    };
    $scope.show = function() {
        $scope.fade = true;
        $scope.getOauth();
    };
    $scope.showAuthDialog = function(ev) {
        $mdDialog.show({
          controller: DialogController,
          templateUrl: 'template/auth.pop.html',
          parent: angular.element(document.body),
          targetEvent: ev,
          clickOutsideToClose:true
        })
        .then(function(answer) {
          $scope.status = 'You said the information was "' + answer + '".';
        }, function() {
          $scope.status = 'You cancelled the dialog.';
        });
    };
}])
// 主面板
.controller('MainCtrl', ['$scope', '$rootScope'  ,'$http', 'KeyNames', '$state',
'$stateParams',
function($scope, $rootScope, $http, KeyNames, $state, $stateParams){
    $scope.authGroup = [
        {name:'消息与菜单权限集', key: 1},
        {name:'帐号管理权限集', key: 2},
        {name:'网页授权权限集', key: 3},
        {name:'微信小店权限集', key: 4},
        {name:'多客服权限集', key: 5},
        {name:'业务通知权限集', key: 6},
        {name:'微信卡券权限集', key: 7},
        {name:'素材管理权限集', key: 8},
        {name:'摇一摇周边权限集', key: 9},
        {name:'线下门店权限集', key: 10},
        {name:'微信连WIFI权限集', key: 11},

    ];
    var appid = $state.params.appid;
    var getBaseInfo = function() {
        $http.get(KeyNames.domain + '/srv/account/info/' + appid)
        .then(function(baseInfo){
            $rootScope.baseInfo = baseInfo.data;
        });
    };
    getBaseInfo();
}])
// 基础信息
.controller('BaseInfoCtrl', ['$scope', '$rootScope', '$http', 'KeyNames', '$state',
'$stateParams',
function($scope, $rootScope, $http, KeyNames, $state, $stateParams){
    //
    var authGroup = $rootScope.baseInfo.authorization_info.func_info;

}]);
<commit_msg>修复初始化root信息错误<commit_after>angular.module('app.ctrl', ['ui.router', 'ngMaterial', 'app.service'])
// 首页
.controller('IndexCtrl',['$scope', '$http', 'KeyNames', '$mdDialog',
function($scope, $http, KeyNames, $mdDialog){
    // $http.get('www.baidu.com');
    var DialogController = function($scope, $http, $mdDialog) {
        $http.get(KeyNames.domain + '/oauth/req')
        .then(function(authLink){
            $scope.authLink = authLink.data.url;
            // window.open('http://wechat.qianmi.com/oauth/req');
        });
        $scope.hide = function() {
            $mdDialog.hide();
        };
        $scope.cancel = function() {
            $mdDialog.cancel();
        };
        $scope.answer = function(answer) {
            $mdDialog.hide(answer);
        };
    };
    $scope.fade = false;
    $scope.getOauth = function() {
        $http.get(KeyNames.domain + '/oauth/req')
        .then(function(authLink){
            $scope.authLink = authLink.data.url;
            // window.open('http://wechat.qianmi.com/oauth/req');
        });
    };
    $scope.show = function() {
        $scope.fade = true;
        $scope.getOauth();
    };
    $scope.showAuthDialog = function(ev) {
        $mdDialog.show({
          controller: DialogController,
          templateUrl: 'template/auth.pop.html',
          parent: angular.element(document.body),
          targetEvent: ev,
          clickOutsideToClose:true
        })
        .then(function(answer) {
          $scope.status = 'You said the information was "' + answer + '".';
        }, function() {
          $scope.status = 'You cancelled the dialog.';
        });
    };
}])
// 主面板
.controller('MainCtrl', ['$scope', '$rootScope'  ,'$http', 'KeyNames', '$state',
'$stateParams',
function($scope, $rootScope, $http, KeyNames, $state, $stateParams){
    $scope.authGroup = [
        {name:'消息与菜单权限集', key: 1},
        {name:'帐号管理权限集', key: 2},
        {name:'网页授权权限集', key: 3},
        {name:'微信小店权限集', key: 4},
        {name:'多客服权限集', key: 5},
        {name:'业务通知权限集', key: 6},
        {name:'微信卡券权限集', key: 7},
        {name:'素材管理权限集', key: 8},
        {name:'摇一摇周边权限集', key: 9},
        {name:'线下门店权限集', key: 10},
        {name:'微信连WIFI权限集', key: 11},

    ];
    var appid = $state.params.appid;
    var getBaseInfo = function() {
        if($rootScope.baseInfo) {

        } else {
            $http.get(KeyNames.domain + '/srv/account/info/' + appid)
            .then(function(baseInfo){
                $rootScope.baseInfo = baseInfo.data;
            });
        }

    };
    getBaseInfo();
}])
// 基础信息
.controller('BaseInfoCtrl', ['$scope', '$rootScope', '$http', 'KeyNames', '$state',
'$stateParams',
function($scope, $rootScope, $http, KeyNames, $state, $stateParams){
    //
    if($rootScope.baseInfo) {

    } else {
        $http.get(KeyNames.domain + '/srv/account/info/' + appid)
        .then(function(baseInfo){
            $rootScope.baseInfo = baseInfo.data;
        });
    }

}]);
<|endoftext|>