<commit_before>// Client-side authentication controller
angular
  .module("SkyTestApp")
  .controller("AuthController", ['$scope', '$http', '$sessionStorage', '$state', function($scope, $http, $sessionStorage, $state) {

    // Model to bind username/password to
    $scope.auth = {};

    // Authentication click handler
    $scope.authenticate = function(auth) {
      // POST the authenication data
      $http
        .post('/authenticate', $scope.auth)
        .success(function (data, status, headers, config) {
          // Receive a JSON Web Token
          $sessionStorage.token = data.token;
          // Redirect to logged in page
          $state.transitionTo('signedin');
        })
        .error(function (data, status, headers, config) {
          // Erase any existing token
          delete $sessionStorage.token;

          // Display an error
          $scope.error = 'Authentication failed, please check your username and password and try again';
        });
    };
  }]);<commit_msg>Add signout button<commit_after>// Client-side authentication controller
angular
  .module("SkyTestApp")
  .controller("AuthController", ['$scope', '$http', '$sessionStorage', '$state', function($scope, $http, $sessionStorage, $state) {

    // Model to bind username/password to
    $scope.auth = {};

    // Authentication click handler
    $scope.authenticate = function(auth) {
      // POST the authenication data
      $http
        .post('/authenticate', $scope.auth)
        .success(function (data, status, headers, config) {
          // Receive a JSON Web Token
          $sessionStorage.token = data.token;
          // Redirect to logged in page
          $state.transitionTo('signedin');
        })
        .error(function (data, status, headers, config) {
          // Erase any existing token
          delete $sessionStorage.token;

          // Display an error
          $scope.error = 'Authentication failed, please check your username and password and try again';
        });
    };

    $scope.signout = function() {
      delete $sessionStorage.token;
      $state.transitionTo('signin');
    };

  }]);<|endoftext|>


<commit_before>import path from 'path';
import program from 'commander';

export function parseList(str) {
  return str.split(',');
}

function getCli() {
  program
    .option('-h, --host <host>', 'host to listen on', 'localhost')
    .option('-p, --port <port>', 'port to listen on', 7007)
    .option('-e, --environment [environment]', 'DEVELOPMENT/PRODUCTION environment for webpack')
    .option('-i, --manual-id', 'allow multiple users to work with same storybook')
    .option('-c, --config-dir [dir-name]', 'Directory where to load Storybook configurations from')
    .option(
      '--https',
      'Serve Storybook over HTTPS. Note: You must provide your own certificate information.'
    )
    .option(
      '--ssl-ca <ca>',
      'Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate)',
      parseList
    )
    .option('--ssl-cert <cert>', 'Provide an SSL certificate. (Required with --https)')
    .option('--ssl-key <key>', 'Provide an SSL key. (Required with --https)')
    .option('--smoke-test', 'Exit after successful start')
    .option('--ci', "CI mode (skip interactive prompts, don't open browser")
    .option('--quiet', 'Suppress verbose build output')
    .parse(process.argv);

  const configDir = path.resolve(program.configDir || './storybook');

  return {
    ...program,
    configDir,
  };
}

export default getCli;
<commit_msg>React-native-server: Convert port to number in CLI options (#8491)<commit_after>import path from 'path';
import program from 'commander';

export function parseList(str) {
  return str.split(',');
}

function getCli() {
  program
    .option('-h, --host <host>', 'host to listen on', 'localhost')
    .option('-p, --port <port>', 'port to listen on', str => parseInt(str, 10), '7007')
    .option('-e, --environment [environment]', 'DEVELOPMENT/PRODUCTION environment for webpack')
    .option('-i, --manual-id', 'allow multiple users to work with same storybook')
    .option('-c, --config-dir [dir-name]', 'Directory where to load Storybook configurations from')
    .option(
      '--https',
      'Serve Storybook over HTTPS. Note: You must provide your own certificate information.'
    )
    .option(
      '--ssl-ca <ca>',
      'Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate)',
      parseList
    )
    .option('--ssl-cert <cert>', 'Provide an SSL certificate. (Required with --https)')
    .option('--ssl-key <key>', 'Provide an SSL key. (Required with --https)')
    .option('--smoke-test', 'Exit after successful start')
    .option('--ci', "CI mode (skip interactive prompts, don't open browser")
    .option('--quiet', 'Suppress verbose build output')
    .parse(process.argv);

  const configDir = path.resolve(program.configDir || './storybook');

  return {
    ...program,
    configDir,
  };
}

export default getCli;
<|endoftext|>


<commit_before>'use strict';

////////////////////////////////////////////////////////////////////////////
// COMMON API - 0.1
// SERVER PUSH CLIENT
// PRIMARY MODULE (AppServerPush)
////////////////////////////////////////////////////////////////////////////
// This module handles server data communication when it pushes them to the client.
// It is based on SocketIO (http://socket.io/). Why?
// Using WebSockets is a modern, bidirectional protocol that enables an interactive communication
// session between the browser and a server. Its main current drawback is
// that implementation is generally only available in the latest browsers. However, by
// using Socket.IO, this low level detail is abstracted away and we, as programmers,
// are relieved of the need to write browser-specific code.
// The current release of socket.io is 0.9.10.
//
// The module AppServerPush is included in the main module.
// The private module AppSocketIO simply wraps SocketIO API to be used by AppServerPush.
// So, AppServerPush is ready to integrate other Server Push approaches (e.g. Atmosphere) only by including
// a new module and injecting it to AppServerPush.
//
//////////////////////////////////////////////////////////////////////////////
// NOTE ABOUT CLIENT DEPENDENCIES WITH SOCKET.IO
// The Socket.IO server will handle serving the correct version of the Socket.IO client library;
// We should not be using one from elsewhere on the Internet. From the top example on http://socket.io/:
//  <script src="/socket.io/socket.io.js"></script>
// This works because we wrap our HTTP server in Socket.IO (see the example at How To Use) and it intercepts
// requests for /socket.io/socket.io.js and sends the appropriate response automatically.
// That is the reason it is not a dependency handled by bower.
////////////////////////////////////////////////////////////////////////////

/**
* @ngdoc module
* @name AppServerPush
* @description
* This module handles server data communication when it pushes them to the client.
*
* It is now based on SocketIO (http://socket.io/). Why?
*
* Using WebSockets is a modern, bidirectional protocol that enables an interactive communication
* session between the browser and a server. Its main current drawback is
* that implementation is generally only available in the latest browsers. However, by
* using Socket.IO, this low level detail is abstracted away and we, as programmers,
* are relieved of the need to write browser-specific code.
*
* The current release of socket.io is 0.9.10.
*
* The module AppServerPush is included in the main module.
*
* The private module AppSocketIO simply wraps SocketIO API to be used by AppServerPush.
*
* So, AppServerPush is ready to integrate other Server Push approaches (e.g. Atmosphere) only by including
* a new module and injecting it to AppServerPush.

* NOTE ABOUT CLIENT DEPENDENCIES WITH SOCKET.IO
* The Socket.IO server will handle serving the correct version of the Socket.IO client library;
*
* We should not be using one from elsewhere on the Internet. From the top example on http://socket.io/:
*
*  <script src="/socket.io/socket.io.js"></script>
*
* This works because we wrap our HTTP server in Socket.IO (see the example at How To Use) and it intercepts
* requests for /socket.io/socket.io.js and sends the appropriate response automatically.
*
* That is the reason it is not a dependency handled by bower.
*/
angular.module('AppServerPush', ['AppSocketIO', 'AppConfiguration'])
/*
     To make socket error events available across an app, in one of the controllers:

     controller('MyCtrl', function ($scope) {
         $scope.on('socket:error', function (ev, data) {
            ...
     });
     */
.run(['$log', 'socket',
    function ($log, socket) {
        $log.info('AppServerPush run');
        socket.forward('error');
    }])
/**
 * @ngdoc service
 * @name AppServerPush.factory:SocketFactory
 * @requires $rootScope
 * @requires socket
 *
 * @description
 * Although Socket.IO exposes an io variable on the window, it's better to encapsulate it
 * into the AngularJS's Dependency Injection system.
 * So, we'll start by writing a factory to wrap the socket object returned by Socket.IO.
 * This will make easier to test the application's controllers.
 * Notice that the factory wrap each socket callback in $scope.$apply.
 * This tells AngularJS that it needs to check the state of the application and update
 * the templates if there was a change after running the callback passed to it by using dirty checking.
 * Internally, $http works in the same way. After some XHR returns, it calls $scope.$apply,
 * so that AngularJS can update its views accordingly.
 */
.factory('SocketFactory', ['$rootScope', 'socket',
        function ($rootScope, socket) {
        var factory = {};

        /*
             @function
             @param eventName the name of the event/channel to be listened
             The communication is bound to rootScope.
             @param callback The function to be passed as callback.
             @description Establishes a communication listening an event/channel from server.
             Use this method for background communication although the current scope is destyroyed.
             You should cancel communication manually or when the $rootScope object is destroyed.
             */
        factory.listen = function (eventName, callback) {
            socket.on(eventName, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    callback.apply(socket, args);
                });
            });
        };

        /*
             @function
             @param eventName the name of the event/channel to be sent to server
             @param scope the scope object to be bound to the listening.
             The communication will be cancelled when the scope is destroyed.
             @param callback The function to be passed as callback.
             @description Establishes a communication listening an event/channel from server.
             It is bound to a given $scope object.
             */
        factory.sendMessage = function (eventName, data, callback) {
            socket.emit(eventName, data, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    if (callback) {
                        callback.apply(socket, args);
                    }
                });
            });
        };

        /*
             @function
             The communication will be cancelled without regarding other consideration.
             No callback is passed.
             @description Cancels all communications to server.
             */
        factory.unsubscribeCommunication = function (callback) {
            socket.off(callback());
        };

        return factory;

        }]);

//////////////////////////////////////////////////////////////////////////////
// COMMON API - 0.1
// PRIVATE MODULE (AppSocketIO)
////////////////////////////////////////////////////////////////////////////

/**
 * @ngdoc module
 * @name AppSocketIO
 * @description
 * Private module implementing SocketIO
 */
angular.module('AppSocketIO', ['AppConfiguration']).

/**
 * @ngdoc service
 * @name AppSocketIO.service:socket
 * @description
 * provides SocketIO client object from pre-existing configuration in application.
 */
provider('socket', ['SERVERPUSH_CONFIG',
    function (SERVERPUSH_CONFIG) {

        // when forwarding events, prefix the event name
        var prefix = 'socket:',
            ioSocket;

        // expose to provider
        this.$get = function ($rootScope, $timeout) {

            /*
            Initialization of the socket object by using params in configuration module.
            Please read below for configuration detals:
            * Client configuration: https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO#client
            * Server configuration: https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO#server
            */
            var socket = ioSocket || io.connect(
                SERVERPUSH_CONFIG.BaseUrl, {
                    'resource': SERVERPUSH_CONFIG.Resource,
                    'connect timeout': SERVERPUSH_CONFIG.ConnectTimeout,
                    'try multiple transports': SERVERPUSH_CONFIG.TryMultipleTransports,
                    'reconnect': SERVERPUSH_CONFIG.Reconnect,
                    'reconnection delay': SERVERPUSH_CONFIG.ReconnectionDelay,
                    'reconnection limit': SERVERPUSH_CONFIG.ReconnectionLimit,
                    'max reconnection attempts': SERVERPUSH_CONFIG.MaxReconnectionAttempts,
                    'sync disconnect on unload': SERVERPUSH_CONFIG.SyncDisconnectOnUnload,
                    'auto connect': SERVERPUSH_CONFIG.AutoConnect,
                    'flash policy port': SERVERPUSH_CONFIG.FlashPolicyPort,
                    'force new connection': SERVERPUSH_CONFIG.ForceNewConnection
                }
            );

            var asyncAngularify = function (callback) {
                return function () {
                    var args = arguments;
                    $timeout(function () {
                        callback.apply(socket, args);
                    }, 0);
                };
            };

            var addListener = function (eventName, callback) {
                socket.on(eventName, asyncAngularify(callback));
            };

            var removeListener = function () {
                socket.removeAllListeners();
            };

            var wrappedSocket = {
                on: addListener,
                addListener: addListener,
                off: removeListener,

                emit: function (eventName, data, callback) {
                    if (callback) {
                        socket.emit(eventName, data, asyncAngularify(callback));
                    } else {
                        socket.emit(eventName, data);
                    }
                },

                //                removeListener: function () {
                //                    var args = arguments;
                //                    return socket.removeListener.apply(socket, args);
                //                },

                forward: function (events, scope) {
                    if (events instanceof Array === false) {
                        events = [events];
                    }
                    if (!scope) {
                        scope = $rootScope;
                    }
                    events.forEach(function (eventName) {
                        var prefixed = prefix + eventName;
                        var forwardEvent = asyncAngularify(function (data) {
                            scope.$broadcast(prefixed, data);
                        });
                        scope.$on('$destroy', function () {
                            socket.removeListener(eventName, forwardEvent);
                        });
                        socket.on(eventName, forwardEvent);
                    });
                }
            };

            return wrappedSocket;
        };

        this.prefix = function (newPrefix) {
            prefix = newPrefix;
        };

        this.ioSocket = function (socket) {
            ioSocket = socket;
        };
    }]);
<commit_msg>Added ngdoc for security and serverpush modules, including soketio private module. Reverted ngdoc socket from service to provider (it is a provider!) <commit_after>'use strict';

////////////////////////////////////////////////////////////////////////////
// COMMON API - 0.1
// SERVER PUSH CLIENT
// PRIMARY MODULE (AppServerPush)
////////////////////////////////////////////////////////////////////////////

/**
* @ngdoc module
* @name AppServerPush
* @description
* This module handles server data communication when it pushes them to the client
* exposing the factory SocketFactory, which is an API for instantiating sockets
* that are integrated with Angular's digest cycle.
* It is now based on SocketIO (http://socket.io/). Why?
*
* Using WebSockets is a modern, bidirectional protocol that enables an interactive communication
* session between the browser and a server. Its main current drawback is
* that implementation is generally only available in the latest browsers. However, by
* using Socket.IO, this low level detail is abstracted away and we, as programmers,
* are relieved of the need to write browser-specific code.
*
* The current release of socket.io is 0.9.10.
*
* The module AppServerPush is included in the main module.
*
* The private module AppSocketIO simply wraps SocketIO API to be used by AppServerPush.
*
* So, AppServerPush is ready to integrate other Server Push approaches (e.g. Atmosphere) only by including
* a new module and injecting it to AppServerPush.
*
*
* NOTE ABOUT CLIENT DEPENDENCIES WITH SOCKET.IO
*
* The Socket.IO server will handle serving the correct version of the Socket.IO client library;
*
* We should not be using one from elsewhere on the Internet. From the top example on http://socket.io/:
*
*  <script src="/socket.io/socket.io.js"></script>
*
* This works because we wrap our HTTP server in Socket.IO (see the example at How To Use) and it intercepts
* requests for /socket.io/socket.io.js and sends the appropriate response automatically.
*
* That is the reason it is not a dependency handled by bower.
*/
angular.module('AppServerPush', ['AppSocketIO', 'AppConfiguration'])
/*
     To make socket error events available across an app, in one of the controllers:

     controller('MyCtrl', function ($scope) {
         $scope.on('socket:error', function (ev, data) {
            ...
     });
     */
.run(['$log', 'socket',
    function ($log, socket) {
        $log.info('AppServerPush run');
        socket.forward('error');
    }])
/**
 * @ngdoc service
 * @name AppServerPush.factory:SocketFactory
 * @requires $rootScope
 * @requires socket
 *
 * @description
 * Although Socket.IO exposes an io variable on the window, it's better to encapsulate it
 * into the AngularJS's Dependency Injection system.
 * So, we'll start by writing a factory to wrap the socket object returned by Socket.IO.
 * This will make easier to test the application's controllers.
 * Notice that the factory wrap each socket callback in $scope.$apply.
 * This tells AngularJS that it needs to check the state of the application and update
 * the templates if there was a change after running the callback passed to it by using dirty checking.
 * Internally, $http works in the same way. After some XHR returns, it calls $scope.$apply,
 * so that AngularJS can update its views accordingly.
 */
.factory('SocketFactory', ['$rootScope', 'socket',
        function ($rootScope, socket) {
        var factory = {};

        /**
             @ngdoc method
             @name AppServerPush.factory:SocketFactory#listen
             @methodOf AppServerPush.factory:SocketFactory
             @param {string} eventName The name of the event/channel to be listened
             The communication is bound to rootScope.
             @param {object} callback The function to be passed as callback.
             @description Establishes a communication listening an event/channel from server.
             Use this method for background communication although the current scope is destyroyed.
             You should cancel communication manually or when the $rootScope object is destroyed.
             */
        factory.listen = function (eventName, callback) {
            socket.on(eventName, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    callback.apply(socket, args);
                });
            });
        };

        /**
             @ngdoc method
             @name AppServerPush.factory:SocketFactory#sendMessage
             @methodOf AppServerPush.factory:SocketFactory
             @param {string} eventName The name of the event/channel to be sent to server
             @param {object} scope The scope object to be bound to the listening.
             The communication will be cancelled when the scope is destroyed.
             @param {object} callback The function to be passed as callback.
             @description Establishes a communication listening an event/channel from server.
             It is bound to a given $scope object.
             */
        factory.sendMessage = function (eventName, data, callback) {
            socket.emit(eventName, data, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    if (callback) {
                        callback.apply(socket, args);
                    }
                });
            });
        };

        /**
             @ngdoc method
             @name AppServerPush.factory:SocketFactory#unsubscribeCommunication
             @methodOf AppServerPush.factory:SocketFactory
             @param {object} callback The function to be passed as callback.
             @description Cancels all communications to server.
             The communication will be cancelled without regarding other consideration.
             */
        factory.unsubscribeCommunication = function (callback) {
            socket.off(callback());
        };

        return factory;

        }]);

//////////////////////////////////////////////////////////////////////////////
// COMMON API - 0.1
// PRIVATE MODULE (AppSocketIO)
////////////////////////////////////////////////////////////////////////////

/**
 * @ngdoc module
 * @name AppSocketIO
 * @description
 * Private module implementing SocketIO. It provides the common API module AppServerpush
 * with the socket object wrapping the SocketIO client. This is initializated according
 * to the pre-existing external configuration.
 */
angular.module('AppSocketIO', ['AppConfiguration'])

/**
 * @ngdoc provider
 * @name AppSocketIO.provider:socket
 * @description
 * This provider provides the appserverpush module with the SocketIO client object from pre-existing configuration in application.
 *
 * This object helps the common API module  making  easier to add/remove listeners in a way that works with AngularJS's scope.
 *
 * socket.on / socket.addListener: Takes an event name and callback. Works just like the method of the same name from Socket.IO.
 *
 * socket.removeListener: Takes an event name and callback. Works just like the method of the same name from Socket.IO.
 *
 * socket.emit: sends a message to the server. Optionally takes a callback.
 * Works just like the method of the same name from Socket.IO.
 *
 * socket.forward: allows you to forward the events received by Socket.IO's socket to AngularJS's event system.
 * You can then listen to the event with $scope.$on. By default, socket-forwarded events are namespaced with socket:.
 * The first argument is a string or array of strings listing the event names to be forwarded.
 * The second argument is optional, and is the scope on which the events are to be broadcast.
 * If an argument is not provided, it defaults to $rootScope.
 * As a reminder, broadcasted events are propagated down to descendant scopes.
 */
 .provider('socket', ['SERVERPUSH_CONFIG',
    function (SERVERPUSH_CONFIG) {

        // when forwarding events, prefix the event name
        var prefix = 'socket:',
            ioSocket;

        // expose to provider
        this.$get = function ($rootScope, $timeout) {

            /*
            Initialization of the socket object by using params in configuration module.
            Please read below for configuration detals:
            * Client configuration: https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO#client
            * Server configuration: https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO#server
            */
            var socket = ioSocket || io.connect(
                SERVERPUSH_CONFIG.BaseUrl, {
                    'resource': SERVERPUSH_CONFIG.Resource,
                    'connect timeout': SERVERPUSH_CONFIG.ConnectTimeout,
                    'try multiple transports': SERVERPUSH_CONFIG.TryMultipleTransports,
                    'reconnect': SERVERPUSH_CONFIG.Reconnect,
                    'reconnection delay': SERVERPUSH_CONFIG.ReconnectionDelay,
                    'reconnection limit': SERVERPUSH_CONFIG.ReconnectionLimit,
                    'max reconnection attempts': SERVERPUSH_CONFIG.MaxReconnectionAttempts,
                    'sync disconnect on unload': SERVERPUSH_CONFIG.SyncDisconnectOnUnload,
                    'auto connect': SERVERPUSH_CONFIG.AutoConnect,
                    'flash policy port': SERVERPUSH_CONFIG.FlashPolicyPort,
                    'force new connection': SERVERPUSH_CONFIG.ForceNewConnection
                }
            );

            var asyncAngularify = function (callback) {
                return function () {
                    var args = arguments;
                    $timeout(function () {
                        callback.apply(socket, args);
                    }, 0);
                };
            };

            var addListener = function (eventName, callback) {
                socket.on(eventName, asyncAngularify(callback));
            };

            var removeListener = function () {
                socket.removeAllListeners();
            };

            var wrappedSocket = {
                on: addListener,
                addListener: addListener,
                off: removeListener,

                emit: function (eventName, data, callback) {
                    if (callback) {
                        socket.emit(eventName, data, asyncAngularify(callback));
                    } else {
                        socket.emit(eventName, data);
                    }
                },

                //                removeListener: function () {
                //                    var args = arguments;
                //                    return socket.removeListener.apply(socket, args);
                //                },

                forward: function (events, scope) {
                    if (events instanceof Array === false) {
                        events = [events];
                    }
                    if (!scope) {
                        scope = $rootScope;
                    }
                    events.forEach(function (eventName) {
                        var prefixed = prefix + eventName;
                        var forwardEvent = asyncAngularify(function (data) {
                            scope.$broadcast(prefixed, data);
                        });
                        scope.$on('$destroy', function () {
                            socket.removeListener(eventName, forwardEvent);
                        });
                        socket.on(eventName, forwardEvent);
                    });
                }
            };

            return wrappedSocket;
        };

        this.prefix = function (newPrefix) {
            prefix = newPrefix;
        };

        this.ioSocket = function (socket) {
            ioSocket = socket;
        };
    }]);
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2015 Laverna project Authors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
/* global define */
define([
    'underscore',
    'q',
    'jquery',
    'backbone.radio',
    'marionette',
    'i18next',
    'apps/notes/form/views/formView',
    'apps/notes/form/views/notebooks'
], function (_, Q, $, Radio, Marionette, i18n, View, NotebooksView) {
    'use strict';

    /**
     * Note form controller.
     *
     * Triggers the following events:
     * 1. channel: notesForm, event: stop
     *
     * Listens to the following events:
     * 1. channel: notes, event: save:after
     *
     * requests:
     * 1. channel: notes, request: save
     *    to save the changes.
     */
    var Controller = Marionette.Object.extend({

        initialize: function(options) {
            this.options = options;

            _.bindAll(this, 'show', 'redirect');

            // Fetch everything
            Q.all([
                Radio.request('notes', 'get:model:full', options),
                Radio.request('notebooks', 'get:all', _.pick(options, 'profile'))
            ])
            .spread(this.show)
            .catch(function() {
                console.error('Editor error', arguments);
            });

            // Events
            this.listenTo(Radio.channel('notes'), 'update:model', this.redirect);
            this.listenTo(Radio.channel('Confirm'), 'confirm', this.redirect);
            this.listenTo(Radio.channel('Confirm'), 'cancel', this.onConfirmCancel);
        },

        onDestroy: function() {
            this.stopListening();
            this.view.trigger('destroy');
        },

        show: function(note, notebooks) {
            var notebooksView;
            note = note[0];

            // Set document title
            Radio.request('global', 'set:title', note.get('title'));

            // Use behaviours that are appropriate for a device.
            if (Radio.request('global', 'platform') === 'mobile') {
                delete View.prototype.behaviors.Desktop;
            }
            else {
                delete View.prototype.behaviors.Mobile;
            }

            this.view = new View({
                model     : note,
                profile   : note.profileId
            });

            // Show the view and trigger an event
            Radio.request('global', 'region:show', 'content', this.view);
            this.view.trigger('rendered');

            /*
             * Resolve the notebook ID.
             * If the current note doesn't have a notebook attached,
             * try to use one from the filter if it specifies a notebook.
             */
            var activeId = note.get('notebookId');
            if (activeId === '0' && this.options.filter === 'notebook') {
                activeId = this.options.query;
            }

            // Show notebooks selector
            notebooksView = new NotebooksView({
                collection : notebooks,
                activeId   : activeId
            });
            this.view.notebooks.show(notebooksView);

            // Listen to view events
            this.listenTo(this.view, 'save', this.save);
            this.listenTo(this.view, 'cancel', this.showConfirm);
        },

        save: function() {
            var self = this;

            return this.getContent()
            .then(function(data) {
                if (data.title === '') {
                    var title = i18n.t('New Note');
                    data.title = title;
                    Radio.request('global', 'set:title', title);
                }
                return Radio.request('notes', 'save', self.view.model, data);
            })
            .fail(function(e) {
                console.error('Error', e);
            });
        },

        getContent: function() {
            var self = this;

            return Radio.request('editor', 'get:data')
            .then(function(data) {
                return _.extend(data, {
                    title      : self.view.ui.title.val().trim(),
                    notebookId : self.view.notebooks.currentView.ui.notebookId.val().trim(),
                });
            });
        },

        /**
         * Warn a user that they have made some changes.
         */
        showConfirm: function() {
            var self = this;

            return this.getContent()
            .then(function(data) {
                var model = self.view.model.pick('title', 'content', 'notebookId');
                data      = _.pick(data, 'title', 'content', 'notebookId');

                // To check if they are equal
                model.content = _.unescape(model.content);
                model.title   = _.unescape(model.title);

                if (_.isEqual(model, data)) {
                    return self.redirect();
                }

                Radio.request('Confirm', 'start', $.t('You have unsaved changes.'));
            })
            .fail(function(e) {
                console.error('form ShowConfirm', e);
            });
        },

        redirect: function() {
            if (!this.view.getOption('redirect')) {
                return;
            }

            // Stop the module and navigate back
            Radio.trigger('notesForm', 'stop');
            Radio.request('uri', 'back');
        },

        onConfirmCancel: function() {
            // Rebind keybindings again because TW bootstrap modal overrites ESC.
            this.view.trigger('bind:keys');
            this.view.options.isClosed = false;

            if (this.view.options.focus !== 'editor') {
                return this.view.ui[this.view.options.focus].focus();
            }
            Radio.trigger('editor', 'focus');
        }

    });

    return Controller;
});
<commit_msg>Change default note name to 'Untitled'<commit_after>/**
 * Copyright (C) 2015 Laverna project Authors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
/* global define */
define([
    'underscore',
    'q',
    'jquery',
    'backbone.radio',
    'marionette',
    'i18next',
    'apps/notes/form/views/formView',
    'apps/notes/form/views/notebooks'
], function (_, Q, $, Radio, Marionette, i18n, View, NotebooksView) {
    'use strict';

    /**
     * Note form controller.
     *
     * Triggers the following events:
     * 1. channel: notesForm, event: stop
     *
     * Listens to the following events:
     * 1. channel: notes, event: save:after
     *
     * requests:
     * 1. channel: notes, request: save
     *    to save the changes.
     */
    var Controller = Marionette.Object.extend({

        initialize: function(options) {
            this.options = options;

            _.bindAll(this, 'show', 'redirect');

            // Fetch everything
            Q.all([
                Radio.request('notes', 'get:model:full', options),
                Radio.request('notebooks', 'get:all', _.pick(options, 'profile'))
            ])
            .spread(this.show)
            .catch(function() {
                console.error('Editor error', arguments);
            });

            // Events
            this.listenTo(Radio.channel('notes'), 'update:model', this.redirect);
            this.listenTo(Radio.channel('Confirm'), 'confirm', this.redirect);
            this.listenTo(Radio.channel('Confirm'), 'cancel', this.onConfirmCancel);
        },

        onDestroy: function() {
            this.stopListening();
            this.view.trigger('destroy');
        },

        show: function(note, notebooks) {
            var notebooksView;
            note = note[0];

            // Set document title
            Radio.request('global', 'set:title', note.get('title'));

            // Use behaviours that are appropriate for a device.
            if (Radio.request('global', 'platform') === 'mobile') {
                delete View.prototype.behaviors.Desktop;
            }
            else {
                delete View.prototype.behaviors.Mobile;
            }

            this.view = new View({
                model     : note,
                profile   : note.profileId
            });

            // Show the view and trigger an event
            Radio.request('global', 'region:show', 'content', this.view);
            this.view.trigger('rendered');

            /*
             * Resolve the notebook ID.
             * If the current note doesn't have a notebook attached,
             * try to use one from the filter if it specifies a notebook.
             */
            var activeId = note.get('notebookId');
            if (activeId === '0' && this.options.filter === 'notebook') {
                activeId = this.options.query;
            }

            // Show notebooks selector
            notebooksView = new NotebooksView({
                collection : notebooks,
                activeId   : activeId
            });
            this.view.notebooks.show(notebooksView);

            // Listen to view events
            this.listenTo(this.view, 'save', this.save);
            this.listenTo(this.view, 'cancel', this.showConfirm);
        },

        save: function() {
            var self = this;

            return this.getContent()
            .then(function(data) {
                if (data.title === '') {
                    var title = i18n.t('Untitled');
                    data.title = title;
                    Radio.request('global', 'set:title', title);
                }
                return Radio.request('notes', 'save', self.view.model, data);
            })
            .fail(function(e) {
                console.error('Error', e);
            });
        },

        getContent: function() {
            var self = this;

            return Radio.request('editor', 'get:data')
            .then(function(data) {
                return _.extend(data, {
                    title      : self.view.ui.title.val().trim(),
                    notebookId : self.view.notebooks.currentView.ui.notebookId.val().trim(),
                });
            });
        },

        /**
         * Warn a user that they have made some changes.
         */
        showConfirm: function() {
            var self = this;

            return this.getContent()
            .then(function(data) {
                var model = self.view.model.pick('title', 'content', 'notebookId');
                data      = _.pick(data, 'title', 'content', 'notebookId');

                // To check if they are equal
                model.content = _.unescape(model.content);
                model.title   = _.unescape(model.title);

                if (_.isEqual(model, data)) {
                    return self.redirect();
                }

                Radio.request('Confirm', 'start', $.t('You have unsaved changes.'));
            })
            .fail(function(e) {
                console.error('form ShowConfirm', e);
            });
        },

        redirect: function() {
            if (!this.view.getOption('redirect')) {
                return;
            }

            // Stop the module and navigate back
            Radio.trigger('notesForm', 'stop');
            Radio.request('uri', 'back');
        },

        onConfirmCancel: function() {
            // Rebind keybindings again because TW bootstrap modal overrites ESC.
            this.view.trigger('bind:keys');
            this.view.options.isClosed = false;

            if (this.view.options.focus !== 'editor') {
                return this.view.ui[this.view.options.focus].focus();
            }
            Radio.trigger('editor', 'focus');
        }

    });

    return Controller;
});
<|endoftext|>


<commit_before>fb_app = {
  current_url: '',

  locales: {

  },

  config: {
    url_prefix: '',
    save_auth_url: '',
    show_login_url: '',

    init: function() {

    },

  },

  timeline: {
    app_id: '',
    //app_scope: 'publish_actions',
    app_scope: '',

    loading: function() {
      jQuery('#fb-app-connect-status').empty().addClass('loading').height(150)
    },

    connect: function() {
      this.loading();
      fb_app.fb.scope = this.app_scope
      //fb_app.fb.init(this.app_id, 'fb_app.fb.connect()')
      fb_app.fb.connect(function (response) {
        fb_app.auth.receive(response)
      });
    },

    disconnect: function() {
      this.loading();
      fb_app.auth.receive({status: 'not_authorized'})
    },

    connect_to_another: function() {
      this.disconnect();
      fb_app.fb.connect_to_another(this.connect)
    },
  },

  page_tab: {
    app_id: '',
    next_url: '',

    init: function() {
    },

    config: {

      init: function() {
        this.change_type($('select#page_tab_config_type'))

      },

      edit: function(button) {
        var page_tab = button.parents('.page-tab')
        page_tab.find('form').toggle(400)
      },

      remove: function(button, url) {
        var page_tab = button.parents('.page-tab')
        var name = page_tab.find('#page_tab_name').val()
        jQuery('.modal-button-yes')
          .attr('target_url',url)
          .attr('target_id','#'+page_tab.attr('id'))
        jQuery('#fb-app-modal-catalog-name').text(name)
        noosfero.modal.html(jQuery('#fb-app-modal-wrap').html())
      },

      remove_confirmed: function(el) {
        el = jQuery(el)
        jQuery.post(el.attr('target_url'), function() {
          var page_tab = jQuery(el.attr('target_id'))
          page_tab.remove()
        })
      },

      close: function(evt) {
       if (evt != null && evt != void 0) { evt.preventDefault(); evt.stopPropagation();}
        noosfero.modal.close()
        jQuery('#content').html('').addClass('loading')
        window.location.href = fb_app.current_url
      },

      validate_catalog_submission: function(form) {
        if (form.find('#page_tab_title').val().trim()=='') {
          noosfero.modal.html('
'+fb_app.locales.error_empty_title+'
')
          return false
        } else {
          var selected_type = form.find('#page_tab_config_type').val()
          var sub_option = form.find('.config-type-'+selected_type+' input')
          if (sub_option.length>0 && sub_option.val().trim()=='') {
            noosfero.modal.html('
'+fb_app.locales.error_empty_settings+'
')
            return false
          }
        }
        return true
      },

      add: function (form) {
        if (!this.validate_catalog_submission(form))
          return false
        // this checks if the user is using FB as a page and offer a switch
        FB.login(function(response) {
          var next_url = fb_app.page_tab.next_url + '?' + form.serialize()
          window.location.href = fb_app.fb.add_tab_url(fb_app.page_tab.app_id, next_url)
        })
        return false
      },

      save: function(form) {
        for (var i=0; tinymce.editors[i]; i++) {
          var editor = tinymce.editors[i]
          editor.save()
        }

        if (!this.validate_catalog_submission(form))
          return false
        jQuery(form).ajaxSubmit({
          dataType: 'script',
        })
        return false
      },

      change_type: function(select) {
        select = jQuery(select)
        var page_tab = select.parents('.page-tab')
        var config_selector = '.config-type-'+select.val()
        var config = page_tab.find(config_selector)
        var to_show = config
        var to_hide = page_tab.find('.config-type:not('+config_selector+')')

        to_show.show().
          find('input').prop('disabled', false)
        to_show.find('.tokenfield').removeClass('disabled')
        to_hide.hide().
          find('input').prop('disabled', true)
      },

      profile: {

        onchange: function(input) {
          if (input.val())
            input.removeAttr('placeholder')
          else
            input.attr('placeholder', input.attr('data-placeholder'))
        },
      },
    },

  },

  auth: {
    status: 'not_authorized',

    load: function (html) {
      jQuery('#fb-app-settings').html(html)
    },
    loadLogin: function (html) {
      if (this.status == 'not_authorized')
        jQuery('#fb-app-connect').html(html).removeClass('loading')
      else
        jQuery('#fb-app-login').html(html)
    },

    receive: function(response) {
      fb_app.fb.authResponse = response
      fb_app.auth.save(response)
    },

    transformParams: function(response) {
      var authResponse = response.authResponse
      if (!authResponse)
        return {auth: {status: response.status}}
      else
        return {
          auth: {
            status: response.status,
            access_token: authResponse.accessToken,
            expires_in: authResponse.expiresIn,
            signed_request: authResponse.signedRequest,
            provider_user_id: authResponse.userID,
          }
        }
    },

    showLogin: function(response) {
      jQuery.get(fb_app.config.show_login_url, this.transformParams(response), this.loadLogin)
    },

    save: function(response) {
      jQuery.post(fb_app.config.save_auth_url, this.transformParams(response), this.load)
    },
  },

  fb: {
    id: '',
    scope: '',

    init: function(app_id, asyncInit) {

      window.fbAsyncInit = function() {
        FB.init({
          appId: app_id,
          status: true,
          cookie: true,
          xfbml: true
        })

        fb_app.fb.size_change()
        jQuery(document).on('DOMNodeInserted', fb_app.fb.size_change)

        if (asyncInit)
          jQuery.globalEval(asyncInit)
      }
    },

    size_change: function() {
      FB.Canvas.setSize({height: jQuery('body').height()+100})
    },

    redirect_to_tab: function(pageID) {
      FB.api('/'+pageID, function(response) {
        window.location.href = response.link + '?sk=app_' + fb_app.fb.id
      })
    },

    add_tab_url: function (app_id, next_url) {
      return 'https://www.facebook.com/dialog/pagetab?' + jQuery.param({app_id: app_id, next: next_url})
    },

    connect: function(callback) {
      FB.login(function(response) {
        if (callback) callback(response)
      }, {scope: fb_app.fb.scope})
    },

    connect_to_another: function(callback) {
      this.logout(this.connect(callback))
    },

    logout: function(callback) {
      // this checks if the user is using FB as a page and offer a switch
      FB.login(function(response) {
        FB.logout(function(response) {
          if (callback) callback(response)
        })
      })
    },

    // not to be used
    delete: function(callback) {
      FB.api("/me/permissions", "DELETE", function(response) {
        if (callback) callback(response)
      })
    },

    checkLoginStatus: function() {
      FB.getLoginStatus(function(response) {
        // don't do nothing, this is just to fetch auth after init
      })
    },

  },

}

<commit_msg>Check if connected<commit_after>fb_app = {
  current_url: '',

  locales: {

  },

  config: {
    url_prefix: '',
    save_auth_url: '',
    show_login_url: '',

    init: function() {

    },

  },

  timeline: {
    app_id: '',
    //app_scope: 'publish_actions',
    app_scope: '',

    loading: function() {
      jQuery('#fb-app-connect-status').empty().addClass('loading').height(150)
    },

    connect: function() {
      this.loading();
      fb_app.fb.scope = this.app_scope
      //fb_app.fb.init(this.app_id, 'fb_app.fb.connect()')
      fb_app.fb.connect(function (response) {
        fb_app.auth.receive(response)
      });
    },

    disconnect: function() {
      this.loading();
      fb_app.auth.receive({status: 'not_authorized'})
    },

    connect_to_another: function() {
      this.disconnect();
      fb_app.fb.connect_to_another(this.connect)
    },
  },

  page_tab: {
    app_id: '',
    next_url: '',

    init: function() {
    },

    config: {

      init: function() {
        this.change_type($('select#page_tab_config_type'))

      },

      edit: function(button) {
        var page_tab = button.parents('.page-tab')
        page_tab.find('form').toggle(400)
      },

      remove: function(button, url) {
        var page_tab = button.parents('.page-tab')
        var name = page_tab.find('#page_tab_name').val()
        jQuery('.modal-button-yes')
          .attr('target_url',url)
          .attr('target_id','#'+page_tab.attr('id'))
        jQuery('#fb-app-modal-catalog-name').text(name)
        noosfero.modal.html(jQuery('#fb-app-modal-wrap').html())
      },

      remove_confirmed: function(el) {
        el = jQuery(el)
        jQuery.post(el.attr('target_url'), function() {
          var page_tab = jQuery(el.attr('target_id'))
          page_tab.remove()
        })
      },

      close: function(evt) {
       if (evt != null && evt != void 0) { evt.preventDefault(); evt.stopPropagation();}
        noosfero.modal.close()
        jQuery('#content').html('').addClass('loading')
        window.location.href = fb_app.current_url
      },

      validate_catalog_submission: function(form) {
        if (form.find('#page_tab_title').val().trim()=='') {
          noosfero.modal.html('
'+fb_app.locales.error_empty_title+'
')
          return false
        } else {
          var selected_type = form.find('#page_tab_config_type').val()
          var sub_option = form.find('.config-type-'+selected_type+' input')
          if (sub_option.length>0 && sub_option.val().trim()=='') {
            noosfero.modal.html('
'+fb_app.locales.error_empty_settings+'
')
            return false
          }
        }
        return true
      },

      add: function (form) {
        if (!this.validate_catalog_submission(form))
          return false
        // this checks if the user is using FB as a page and offer a switch
        FB.login(function(response) {
          if (response.status != 'connected') return
          var next_url = fb_app.page_tab.next_url + '?' + form.serialize()
          window.location.href = fb_app.fb.add_tab_url(fb_app.page_tab.app_id, next_url)
        })
        return false
      },

      save: function(form) {
        for (var i=0; tinymce.editors[i]; i++) {
          var editor = tinymce.editors[i]
          editor.save()
        }

        if (!this.validate_catalog_submission(form))
          return false
        jQuery(form).ajaxSubmit({
          dataType: 'script',
        })
        return false
      },

      change_type: function(select) {
        select = jQuery(select)
        var page_tab = select.parents('.page-tab')
        var config_selector = '.config-type-'+select.val()
        var config = page_tab.find(config_selector)
        var to_show = config
        var to_hide = page_tab.find('.config-type:not('+config_selector+')')

        to_show.show().
          find('input').prop('disabled', false)
        to_show.find('.tokenfield').removeClass('disabled')
        to_hide.hide().
          find('input').prop('disabled', true)
      },

      profile: {

        onchange: function(input) {
          if (input.val())
            input.removeAttr('placeholder')
          else
            input.attr('placeholder', input.attr('data-placeholder'))
        },
      },
    },

  },

  auth: {
    status: 'not_authorized',

    load: function (html) {
      jQuery('#fb-app-settings').html(html)
    },
    loadLogin: function (html) {
      if (this.status == 'not_authorized')
        jQuery('#fb-app-connect').html(html).removeClass('loading')
      else
        jQuery('#fb-app-login').html(html)
    },

    receive: function(response) {
      fb_app.fb.authResponse = response
      fb_app.auth.save(response)
    },

    transformParams: function(response) {
      var authResponse = response.authResponse
      if (!authResponse)
        return {auth: {status: response.status}}
      else
        return {
          auth: {
            status: response.status,
            access_token: authResponse.accessToken,
            expires_in: authResponse.expiresIn,
            signed_request: authResponse.signedRequest,
            provider_user_id: authResponse.userID,
          }
        }
    },

    showLogin: function(response) {
      jQuery.get(fb_app.config.show_login_url, this.transformParams(response), this.loadLogin)
    },

    save: function(response) {
      jQuery.post(fb_app.config.save_auth_url, this.transformParams(response), this.load)
    },
  },

  fb: {
    id: '',
    scope: '',

    init: function(app_id, asyncInit) {

      window.fbAsyncInit = function() {
        FB.init({
          appId: app_id,
          status: true,
          cookie: true,
          xfbml: true
        })

        fb_app.fb.size_change()
        jQuery(document).on('DOMNodeInserted', fb_app.fb.size_change)

        if (asyncInit)
          jQuery.globalEval(asyncInit)
      }
    },

    size_change: function() {
      FB.Canvas.setSize({height: jQuery('body').height()+100})
    },

    redirect_to_tab: function(pageID) {
      FB.api('/'+pageID, function(response) {
        window.location.href = response.link + '?sk=app_' + fb_app.fb.id
      })
    },

    add_tab_url: function (app_id, next_url) {
      return 'https://www.facebook.com/dialog/pagetab?' + jQuery.param({app_id: app_id, next: next_url})
    },

    connect: function(callback) {
      FB.login(function(response) {
        if (callback) callback(response)
      }, {scope: fb_app.fb.scope})
    },

    connect_to_another: function(callback) {
      this.logout(this.connect(callback))
    },

    logout: function(callback) {
      // this checks if the user is using FB as a page and offer a switch
      FB.login(function(response) {
        FB.logout(function(response) {
          if (callback) callback(response)
        })
      })
    },

    // not to be used
    delete: function(callback) {
      FB.api("/me/permissions", "DELETE", function(response) {
        if (callback) callback(response)
      })
    },

    checkLoginStatus: function() {
      FB.getLoginStatus(function(response) {
        // don't do nothing, this is just to fetch auth after init
      })
    },

  },

}

<|endoftext|>


<commit_before>define([
    'lodash',
    'jquery',
    'angular',
    'moment',
    'd3'
], function(_, $, angular, moment, d3) {
    'use strict';

    angular.module('superdesk.items.directives', ['ui.bootstrap']).
        filter('reldate', function() {
            return function(date) {
                return moment(date).fromNow();
            };
        }).
        directive('sdSearchbar', function($location, $routeParams) {
            return {
                scope: {
                    df: '@'
                },
                link: function(scope, element, attrs) {
                    element.attr('name', 'searchbar');
                    element.attr('autofocus', 'autofocus');
                    element.addClass('searchbar-container');
                    element.val($routeParams.q || '');

                    element.change(function() {
                        scope.$apply(function() {
                            var query = element.val();
                            if (query && query.length > 2) {
                                $location.search('q', query);
                                $location.search('page', null);
                                $location.search('df', scope.df);
                            } else if (query.length === 0) {
                                $location.search('q', null);
                                $location.search('page', null);
                                $location.search('df', null);
                            }
                        });
                    });
                }
            };
        }).
        directive('sdHtml', function($sce) {
            return {
                require: '?ngModel',
                link: function($scope, element, attrs, ngModel) {
                    ngModel.$render = function() {
                        element.prepend(ngModel.$viewValue);
                    };
                }
            };
        }).
        directive('sdContent', function() {
            function getText(content) {
                var lines = $(content);
                var texts = [];
                for (var i = 0; i < lines.length; i++) {
                    var el = $(lines[i]);
                    if (el.is('p')) {
                        texts.push(el[0].outerHTML);
                    }
                }

                return texts.join('\n');
            }

            return {
                require: '?ngModel',
                link: function($scope, element, attrs, ngModel) {
                    ngModel.$render = function() {
                        element.html(getText(ngModel.$viewValue.content));
                    };
                }
            };
        })
        .directive('sdMediaBox', function($position){
            return {
                restrict : 'A',
                template: '

',
                link: function(scope, element, attrs) {

                    scope.$watch('ui.view', function(view) {
                        switch(view) {
                        case 'list':
                            scope.itemTemplate = 'scripts/superdesk-items/views/media-box-list.html';
                            break;
                        default:
                            scope.itemTemplate = 'scripts/superdesk-items/views/media-box-grid.html';
                        }
                    });

                    scope.hoverItem = function(item) {
                        var pos = $position.position(element.find('.media-box'));
                        scope.selectedItem.item = item;
                        scope.selectedItem.position = {left: pos.left - 9, top: pos.top - 15};
                        scope.selectedItem.show = true;
                    };
                }
            };
        })
        .directive('sdMediaBoxHover', function($position){
            return {
                restrict : 'A',
                templateUrl : 'scripts/superdesk-items/views/media-box-hover.html',
                replace : true,
                link: function(scope, element, attrs) {
                }
            };
        })
        .directive('sdItemList', function($routeParams, $location, storage) {
            return {
                templateUrl: 'scripts/superdesk-items/views/item-list.html',
                link: function(scope, element, attrs) {
                    function getSetting(key, def) {
                        var val = storage.getItem(key);
                        return (val === null) ? def : val;
                    }

                    scope.selectedItem = {
                        item: null,
                        position: {
                            left: 0,
                            top: 0
                        },
                        show: false
                    };

                    scope.ui = {
                        compact: getSetting('archive:compact', false),
                        view: $routeParams.view || 'grid'
                    };

                    var actions = attrs.actions.split(',');
                    scope.actions = _.zipObject(actions, _.range(1, actions.length + 1, 0));

                    scope.toggleCompact = function() {
                        scope.ui.compact = !scope.ui.compact;
                        storage.setItem('archive:compact', scope.ui.compact, true);
                    };

                    scope.setView = function(val) {
                        scope.view = val;
                        $location.search('view', val !== 'grid' ? val : null);
                    };

                    scope.preview = function(item) {
                        scope.previewItem = item;
                        scope.previewSingle = item;

                        if (item.type === 'composite') {
                            scope.previewSingle = null;
                            scope.previewItem.packageRefs = item.groups[_.findKey(item.groups,{id:'main'})].refs;
                        }
                    };

                }
            };
        })
        .directive('sdItemPreview', function(em) {
            return {
                templateUrl: 'scripts/superdesk-items/views/item-preview.html',
                replace: true,
                scope: {
                    item: '=',
                    previewSingle : '=previewitem'
                },
                link: function(scope, element, attrs) {
                    scope.closeEdit = function() {
                        scope.item = null;
                        scope.previewSingle = null;
                    };
                    scope.treepreview = function(item) {
                        scope.previewSingle = item;
                    };
                    scope.archive = function(item) {
                        em.create('archive', item).then(function() {
                            item.archived = true;
                        });
                    };
                }
            };
        })
        .directive('sdRef',function(em){
            return {
                link: function(scope, element, attrs) {
                    scope.$watch('ref', function(ref) {
                        em.getRepository('ingest').find(ref.residRef).then(function(item) {
                            scope.refItem = item;
                        });
                    });

                }
            };
        })
        .directive('sdProviderFilter', function($routeParams, $location, providerRepository) {
            return {
                scope: {items: '='},
                templateUrl: 'scripts/superdesk-items/views/provider-filter.html',
                link: function(scope, element, attrs) {
                    scope.activeProvider = $routeParams.provider || null;
                    scope.setProvider = function(provider) {
                        $location.search('provider', provider);
                    };
                }
            };
        })
        .directive('sdPieChart', function() {
            return {
                scope: {
                    terms: '='
                },
                link: function(scope, element, attrs) {

                    // todo define chart css
                    element
                        .css('background-color', '#fff')
                        .css('float', 'left')
                        .css('margin', '10px 0 0 10px');

                    var width = 320 * (attrs.x ? parseInt(attrs.x, 10) : 1),
                        height = 250 * (attrs.y ? parseInt(attrs.y, 10) : 1),
                        radius = Math.min(width, height) / 2;

                    var color = d3.scale.category10();

                    var arc = d3.svg.arc()
                        .outerRadius(radius - 10)
                        .innerRadius(radius * 8 / 13 / 2);

                    var sort = attrs.sort || null;
                    var pie = d3.layout.pie()
                        .value(function(d) { return d.count; })
                        .sort(sort ? function(a, b) { return d3.ascending(a[sort], b[sort]); } : null);

                    var svg = d3.select(element[0]).append('svg')
                        .attr('width', width)
                        .attr('height', height)
                        .append('g')
                        .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');

                    scope.$watch('terms', function(terms) {
                        var g = svg.selectAll('.arc')
                            .data(pie(terms))
                            .enter().append('g')
                            .attr('class', 'arc');

                        g.append('path')
                            .attr('d', arc)
                            .style('fill', function(d) { return color(d.data.term); });

                        g.append('text')
                            .attr('transform', function(d) { return 'translate(' + arc.centroid(d) + ')'; })
                            .attr('dy', '.35em')
                            .style('text-anchor', 'middle')
                            .text(function(d) { return d.data.term; });
                    });
                }
            };
        })
        .directive('sdHistogram', function() {
            return {
                scope: {
                    entries: '='
                },
                link: function(scope, element, attrs) {
                    // todo define chart css
                    element
                        .css('background-color', '#fff')
                        .css('float', 'left')
                        .css('margin', '10px 0 0 10px');

                    var width = 320 * (attrs.x ? parseInt(attrs.x, 10) : 1),
                        barHeight = 30,
                        x = d3.scale.linear().range([0, width - 10]);

                    var color = d3.scale.category10();

                    var svg = d3.select(element[0]).append('svg')
                        .attr('width', width);

                    scope.$watch('entries', function(entries) {
                        var data = _.last(entries, 24);
                        data.reverse();
                        x.domain([0, d3.max(data, function(d) { return d.count; })]);
                        svg.attr('height', barHeight * data.length + 5);

                        var bar = svg.selectAll('.bar')
                            .data(data)
                            .enter().append('g')
                            .attr('class', 'bar')
                            .attr('transform', function(d, i) { return 'translate(5,' + (5 + i * barHeight) + ')'; });

                        bar.append('rect')
                            .attr('width', function(d) { return x(d.count); })
                            .attr('height', barHeight - 1)
                            .style('fill', function(d) { return color(d.time); });

                        bar.append('text')
                            .attr('x', 3)
                            .attr('y', barHeight / 2)
                            .attr('dy', '.35em')
                            .text(function(d) { return d.count + ' / ' + moment.unix(d.time / 1000).format('HH:mm') + '+'; });
                    });
                }
            };
        })
        .directive('sdSource', function($sce) {
            var typeMap = {
                'video/mpeg': 'video/mp4'
            };

            return {
                scope: {
                    sdSource: '='
                },
                link: function(scope, element) {
                    scope.$watch('sdSource', function(source) {
                        element.empty();
                        if (source) {
                            angular.element('<source />')
                                .attr('type', typeMap[source.mimetype] || source.mimetype)
                                .attr('src', source.href)
                                .appendTo(element);
                        }
                    });
                }
            };
        })
        .directive('sdPieChart', function() {
            return {
                scope: {
                    terms: '='
                },
                link: function(scope, element, attrs) {

                    // todo define chart css
                    element
                        .css('background-color', '#fff')
                        .css('float', 'left')
                        .css('margin', '10px 0 0 10px');

                    var width = 320 * (attrs.x ? parseInt(attrs.x, 10) : 1),
                        height = 250 * (attrs.y ? parseInt(attrs.y, 10) : 1),
                        radius = Math.min(width, height) / 2;

                    var color = d3.scale.category10();

                    var arc = d3.svg.arc()
                        .outerRadius(radius - 10)
                        .innerRadius(radius * 8 / 13 / 2);

                    var sort = attrs.sort || null;
                    var pie = d3.layout.pie()
                        .value(function(d) { return d.count; })
                        .sort(sort ? function(a, b) { return d3.ascending(a[sort], b[sort]); } : null);

                    var svg = d3.select(element[0]).append('svg')
                        .attr('width', width)
                        .attr('height', height)
                        .append('g')
                        .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');

                    scope.$watch('terms', function(terms) {
                        var g = svg.selectAll('.arc')
                            .data(pie(terms))
                            .enter().append('g')
                            .attr('class', 'arc');

                        g.append('path')
                            .attr('d', arc)
                            .style('fill', function(d) { return color(d.data.term); });

                        g.append('text')
                            .attr('transform', function(d) { return 'translate(' + arc.centroid(d) + ')'; })
                            .attr('dy', '.35em')
                            .style('text-anchor', 'middle')
                            .text(function(d) { return d.data.term; });
                    });
                }
            };
        });
});<commit_msg>Remove duplicated directive.<commit_after>define([
    'lodash',
    'jquery',
    'angular',
    'moment',
    'd3'
], function(_, $, angular, moment, d3) {
    'use strict';

    angular.module('superdesk.items.directives', ['ui.bootstrap']).
        filter('reldate', function() {
            return function(date) {
                return moment(date).fromNow();
            };
        }).
        directive('sdSearchbar', function($location, $routeParams) {
            return {
                scope: {
                    df: '@'
                },
                link: function(scope, element, attrs) {
                    element.attr('name', 'searchbar');
                    element.attr('autofocus', 'autofocus');
                    element.addClass('searchbar-container');
                    element.val($routeParams.q || '');

                    element.change(function() {
                        scope.$apply(function() {
                            var query = element.val();
                            if (query && query.length > 2) {
                                $location.search('q', query);
                                $location.search('page', null);
                                $location.search('df', scope.df);
                            } else if (query.length === 0) {
                                $location.search('q', null);
                                $location.search('page', null);
                                $location.search('df', null);
                            }
                        });
                    });
                }
            };
        }).
        directive('sdHtml', function($sce) {
            return {
                require: '?ngModel',
                link: function($scope, element, attrs, ngModel) {
                    ngModel.$render = function() {
                        element.prepend(ngModel.$viewValue);
                    };
                }
            };
        }).
        directive('sdContent', function() {
            function getText(content) {
                var lines = $(content);
                var texts = [];
                for (var i = 0; i < lines.length; i++) {
                    var el = $(lines[i]);
                    if (el.is('p')) {
                        texts.push(el[0].outerHTML);
                    }
                }

                return texts.join('\n');
            }

            return {
                require: '?ngModel',
                link: function($scope, element, attrs, ngModel) {
                    ngModel.$render = function() {
                        element.html(getText(ngModel.$viewValue.content));
                    };
                }
            };
        })
        .directive('sdMediaBox', function($position){
            return {
                restrict : 'A',
                template: '

',
                link: function(scope, element, attrs) {

                    scope.$watch('ui.view', function(view) {
                        switch(view) {
                        case 'list':
                            scope.itemTemplate = 'scripts/superdesk-items/views/media-box-list.html';
                            break;
                        default:
                            scope.itemTemplate = 'scripts/superdesk-items/views/media-box-grid.html';
                        }
                    });

                    scope.hoverItem = function(item) {
                        var pos = $position.position(element.find('.media-box'));
                        scope.selectedItem.item = item;
                        scope.selectedItem.position = {left: pos.left - 9, top: pos.top - 15};
                        scope.selectedItem.show = true;
                    };
                }
            };
        })
        .directive('sdMediaBoxHover', function($position){
            return {
                restrict : 'A',
                templateUrl : 'scripts/superdesk-items/views/media-box-hover.html',
                replace : true,
                link: function(scope, element, attrs) {
                }
            };
        })
        .directive('sdItemList', function($routeParams, $location, storage) {
            return {
                templateUrl: 'scripts/superdesk-items/views/item-list.html',
                link: function(scope, element, attrs) {
                    function getSetting(key, def) {
                        var val = storage.getItem(key);
                        return (val === null) ? def : val;
                    }

                    scope.selectedItem = {
                        item: null,
                        position: {
                            left: 0,
                            top: 0
                        },
                        show: false
                    };

                    scope.ui = {
                        compact: getSetting('archive:compact', false),
                        view: $routeParams.view || 'grid'
                    };

                    var actions = attrs.actions.split(',');
                    scope.actions = _.zipObject(actions, _.range(1, actions.length + 1, 0));

                    scope.toggleCompact = function() {
                        scope.ui.compact = !scope.ui.compact;
                        storage.setItem('archive:compact', scope.ui.compact, true);
                    };

                    scope.setView = function(val) {
                        scope.view = val;
                        $location.search('view', val !== 'grid' ? val : null);
                    };

                    scope.preview = function(item) {
                        scope.previewItem = item;
                        scope.previewSingle = item;

                        if (item.type === 'composite') {
                            scope.previewSingle = null;
                            scope.previewItem.packageRefs = item.groups[_.findKey(item.groups,{id:'main'})].refs;
                        }
                    };

                }
            };
        })
        .directive('sdItemPreview', function(em) {
            return {
                templateUrl: 'scripts/superdesk-items/views/item-preview.html',
                replace: true,
                scope: {
                    item: '=',
                    previewSingle : '=previewitem'
                },
                link: function(scope, element, attrs) {
                    scope.closeEdit = function() {
                        scope.item = null;
                        scope.previewSingle = null;
                    };
                    scope.treepreview = function(item) {
                        scope.previewSingle = item;
                    };
                    scope.archive = function(item) {
                        em.create('archive', item).then(function() {
                            item.archived = true;
                        });
                    };
                }
            };
        })
        .directive('sdRef',function(em){
            return {
                link: function(scope, element, attrs) {
                    scope.$watch('ref', function(ref) {
                        em.getRepository('ingest').find(ref.residRef).then(function(item) {
                            scope.refItem = item;
                        });
                    });

                }
            };
        })
        .directive('sdProviderFilter', function($routeParams, $location, providerRepository) {
            return {
                scope: {items: '='},
                templateUrl: 'scripts/superdesk-items/views/provider-filter.html',
                link: function(scope, element, attrs) {
                    scope.activeProvider = $routeParams.provider || null;
                    scope.setProvider = function(provider) {
                        $location.search('provider', provider);
                    };
                }
            };
        })
        .directive('sdPieChart', function() {
            return {
                scope: {
                    terms: '='
                },
                link: function(scope, element, attrs) {

                    // todo define chart css
                    element
                        .css('background-color', '#fff')
                        .css('float', 'left')
                        .css('margin', '10px 0 0 10px');

                    var width = 320 * (attrs.x ? parseInt(attrs.x, 10) : 1),
                        height = 250 * (attrs.y ? parseInt(attrs.y, 10) : 1),
                        radius = Math.min(width, height) / 2;

                    var color = d3.scale.category10();

                    var arc = d3.svg.arc()
                        .outerRadius(radius - 10)
                        .innerRadius(radius * 8 / 13 / 2);

                    var sort = attrs.sort || null;
                    var pie = d3.layout.pie()
                        .value(function(d) { return d.count; })
                        .sort(sort ? function(a, b) { return d3.ascending(a[sort], b[sort]); } : null);

                    var svg = d3.select(element[0]).append('svg')
                        .attr('width', width)
                        .attr('height', height)
                        .append('g')
                        .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');

                    scope.$watch('terms', function(terms) {
                        var g = svg.selectAll('.arc')
                            .data(pie(terms))
                            .enter().append('g')
                            .attr('class', 'arc');

                        g.append('path')
                            .attr('d', arc)
                            .style('fill', function(d) { return color(d.data.term); });

                        g.append('text')
                            .attr('transform', function(d) { return 'translate(' + arc.centroid(d) + ')'; })
                            .attr('dy', '.35em')
                            .style('text-anchor', 'middle')
                            .text(function(d) { return d.data.term; });
                    });
                }
            };
        })
        .directive('sdHistogram', function() {
            return {
                scope: {
                    entries: '='
                },
                link: function(scope, element, attrs) {
                    // todo define chart css
                    element
                        .css('background-color', '#fff')
                        .css('float', 'left')
                        .css('margin', '10px 0 0 10px');

                    var width = 320 * (attrs.x ? parseInt(attrs.x, 10) : 1),
                        barHeight = 30,
                        x = d3.scale.linear().range([0, width - 10]);

                    var color = d3.scale.category10();

                    var svg = d3.select(element[0]).append('svg')
                        .attr('width', width);

                    scope.$watch('entries', function(entries) {
                        var data = _.last(entries, 24);
                        data.reverse();
                        x.domain([0, d3.max(data, function(d) { return d.count; })]);
                        svg.attr('height', barHeight * data.length + 5);

                        var bar = svg.selectAll('.bar')
                            .data(data)
                            .enter().append('g')
                            .attr('class', 'bar')
                            .attr('transform', function(d, i) { return 'translate(5,' + (5 + i * barHeight) + ')'; });

                        bar.append('rect')
                            .attr('width', function(d) { return x(d.count); })
                            .attr('height', barHeight - 1)
                            .style('fill', function(d) { return color(d.time); });

                        bar.append('text')
                            .attr('x', 3)
                            .attr('y', barHeight / 2)
                            .attr('dy', '.35em')
                            .text(function(d) { return d.count + ' / ' + moment.unix(d.time / 1000).format('HH:mm') + '+'; });
                    });
                }
            };
        })
        .directive('sdSource', function($sce) {
            var typeMap = {
                'video/mpeg': 'video/mp4'
            };

            return {
                scope: {
                    sdSource: '='
                },
                link: function(scope, element) {
                    scope.$watch('sdSource', function(source) {
                        element.empty();
                        if (source) {
                            angular.element('<source />')
                                .attr('type', typeMap[source.mimetype] || source.mimetype)
                                .attr('src', source.href)
                                .appendTo(element);
                        }
                    });
                }
            };
        });
});<|endoftext|>