<commit_before>// Generated on 2014-05-04 using generator-angular 0.8.0
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    // Define the configuration for all the tasks
    grunt.initConfig({

        // Project settings
        yeoman: {
            // configurable paths
            app: require('./bower.json').appPath || 'app',
            dist: 'dist'
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {
            bower: {
                files: ['bower.json'],
                tasks: ['bowerInstall']
            },
            js: {
                files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
                tasks: ['newer:jshint:all'],
                options: {
                    livereload: true
                }
            },
            jsTest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['newer:jshint:test', 'karma']
            },
            compass: {
                files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
                tasks: ['compass:server', 'autoprefixer']
            },
            gruntfile: {
                files: ['Gruntfile.js']
            },
            livereload: {
                options: {
                    livereload: '<%= connect.options.livereload %>'
                },
                files: [
                    '<%= yeoman.app %>/{,*/}*.html',
                    '.tmp/styles/{,*/}*.css',
                    '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
                ]
            }
        },

        // The actual grunt server settings
        connect: {
            options: {
                port: 9000,
                // Change this to '0.0.0.0' to access the server from outside.
                hostname: 'localhost',
                livereload: 35729
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        '.tmp',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            test: {
                options: {
                    port: 9001,
                    base: [
                        '.tmp',
                        'test',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            dist: {
                options: {
                    base: '<%= yeoman.dist %>'
                }
            }
        },

        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                reporter: require('jshint-stylish')
            },
            all: [
                'Gruntfile.js',
                '<%= yeoman.app %>/scripts/{,*/}*.js'
            ],
            test: {
                options: {
                    jshintrc: 'test/.jshintrc'
                },
                src: ['test/spec/{,*/}*.js']
            }
        },

        // Empties folders to start fresh
        clean: {
            dist: {
                files: [
                    {
                        dot: true,
                        src: [
                            '.tmp',
                            '<%= yeoman.dist %>/*',
                            '!<%= yeoman.dist %>/.git*'
                        ]
                    }
                ]
            },
            server: '.tmp'
        },

        // Add vendor prefixed styles
        autoprefixer: {
            options: {
                browsers: ['last 1 version']
            },
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '.tmp/styles/',
                        src: '{,*/}*.css',
                        dest: '.tmp/styles/'
                    }
                ]
            }
        },

        // Automatically inject Bower components into the app
        bowerInstall: {
            app: {
                src: ['<%= yeoman.app %>/index.html'],
                ignorePath: '<%= yeoman.app %>/'
            },
            sass: {
                src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
                ignorePath: '<%= yeoman.app %>/bower_components/'
            }
        },

        // Compiles Sass to CSS and generates necessary files if requested
        compass: {
            options: {
                sassDir: '<%= yeoman.app %>/styles',
                cssDir: '.tmp/styles',
                generatedImagesDir: '.tmp/images/generated',
                imagesDir: '<%= yeoman.app %>/images',
                javascriptsDir: '<%= yeoman.app %>/scripts',
                fontsDir: '<%= yeoman.app %>/styles/fonts',
                importPath: '<%= yeoman.app %>/bower_components',
                httpImagesPath: '/images',
                httpGeneratedImagesPath: '/images/generated',
                httpFontsPath: '/styles/fonts',
                relativeAssets: false,
                assetCacheBuster: false,
                raw: 'Sass::Script::Number.precision = 10\n'
            },
            dist: {
                options: {
                    generatedImagesDir: '<%= yeoman.dist %>/images/generated'
                }
            },
            server: {
                options: {
                    debugInfo: true
                }
            }
        },

        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= yeoman.dist %>/scripts/{,*/}*.js',
                        '<%= yeoman.dist %>/styles/{,*/}*.css',
                        '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%= yeoman.dist %>/styles/fonts/*'
                    ]
                }
            }
        },

        // Reads HTML for usemin blocks to enable smart builds that automatically
        // concat, minify and revision files. Creates configurations in memory so
        // additional tasks can operate on them
        useminPrepare: {
            html: '<%= yeoman.app %>/index.html',
            options: {
                dest: '<%= yeoman.dist %>',
                flow: {
                    html: {
                        steps: {
                            js: ['concat', 'uglifyjs'],
                            css: ['cssmin']
                        },
                        post: {}
                    }
                }
            }
        },

        // Performs rewrites based on rev and the useminPrepare configuration
        usemin: {
            html: ['<%= yeoman.dist %>/{,*/}*.html'],
            css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
            options: {
                assetsDirs: ['<%= yeoman.dist %>']
            }
        },

        // The following *-min tasks produce minified files in the dist folder
        cssmin: {
            options: {
                root: '<%= yeoman.app %>'
            }
        },

        imagemin: {
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.app %>/images',
                        src: '{,*/}*.{png,jpg,jpeg,gif}',
                        dest: '<%= yeoman.dist %>/images'
                    }
                ]
            }
        },

        svgmin: {
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.app %>/images',
                        src: '{,*/}*.svg',
                        dest: '<%= yeoman.dist %>/images'
                    }
                ]
            }
        },

        htmlmin: {
            dist: {
                options: {
                    collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    removeCommentsFromCDATA: true,
                    removeOptionalTags: true
                },
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.dist %>',
                        src: ['*.html', 'views/{,*/}*.html'],
                        dest: '<%= yeoman.dist %>'
                    }
                ]
            }
        },

        // ngmin tries to make the code safe for minification automatically by
        // using the Angular long form for dependency injection. It doesn't work on
        // things like resolve or inject so those have to be done manually.
        ngmin: {
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '.tmp/concat/scripts',
                        src: '*.js',
                        dest: '.tmp/concat/scripts'
                    }
                ]
            }
        },

        // Replace Google CDN references
        cdnify: {
            dist: {
                html: ['<%= yeoman.dist %>/*.html']
            }
        },

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [
                    {
                        expand: true,
                        dot: true,
                        cwd: '<%= yeoman.app %>',
                        dest: '<%= yeoman.dist %>',
                        src: [
                            '*.{ico,png,txt}',
                            '.htaccess',
                            '*.html',
                            'views/{,*/}*.html',
                            'images/{,*/}*.{webp}',
                            'fonts/*'
                        ]
                    },
                    {
                        expand: true,
                        cwd: '.tmp/images',
                        dest: '<%= yeoman.dist %>/images',
                        src: ['generated/*']
                    }
                ]
            },
            styles: {
                expand: true,
                cwd: '<%= yeoman.app %>/styles',
                dest: '.tmp/styles/',
                src: '{,*/}*.css'
            }
        },

        // Run some tasks in parallel to speed up the build process
        concurrent: {
            server: [
                'compass:server'
            ],
            test: [
                'compass'
            ],
            dist: [
                'compass:dist',
                'imagemin',
                'svgmin'
            ]
        },

        // By default, your `index.html`'s <!-- Usemin block --> will take care of
        // minification. These next options are pre-configured if you do not wish
        // to use the Usemin blocks.
        // cssmin: {
        //   dist: {
        //     files: {
        //       '<%= yeoman.dist %>/styles/main.css': [
        //         '.tmp/styles/{,*/}*.css',
        //         '<%= yeoman.app %>/styles/{,*/}*.css'
        //       ]
        //     }
        //   }
        // },
        // uglify: {
        //   dist: {
        //     files: {
        //       '<%= yeoman.dist %>/scripts/scripts.js': [
        //         '<%= yeoman.dist %>/scripts/scripts.js'
        //       ]
        //     }
        //   }
        // },
        // concat: {
        //   dist: {}
        // },

        // Test settings
        karma: {
            unit: {
                configFile: 'karma.conf.js',
                singleRun: true
            }
        }
    });

    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'bowerInstall',
            'concurrent:server',
            'autoprefixer',
            'connect:livereload',
            'watch'
        ]);
    });

    grunt.registerTask('server', function (target) {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run(['serve:' + target]);
    });

    grunt.registerTask('test', [
        'clean:server',
        'concurrent:test',
        'autoprefixer',
        'connect:test',
        'karma'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'bowerInstall',
        'useminPrepare',
        'concurrent:dist',
        'autoprefixer',
        'concat',
        'ngmin',
        'copy:dist',
        'cdnify',
        'cssmin',
        'uglify',
        'rev',
        'usemin',
        'htmlmin'
    ]);

    grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
    ]);
};
<commit_msg>Registering lightweight travis test grunt task<commit_after>// Generated on 2014-05-04 using generator-angular 0.8.0
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    // Define the configuration for all the tasks
    grunt.initConfig({

        // Project settings
        yeoman: {
            // configurable paths
            app: require('./bower.json').appPath || 'app',
            dist: 'dist'
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {
            bower: {
                files: ['bower.json'],
                tasks: ['bowerInstall']
            },
            js: {
                files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
                tasks: ['newer:jshint:all'],
                options: {
                    livereload: true
                }
            },
            jsTest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['newer:jshint:test', 'karma']
            },
            compass: {
                files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
                tasks: ['compass:server', 'autoprefixer']
            },
            gruntfile: {
                files: ['Gruntfile.js']
            },
            livereload: {
                options: {
                    livereload: '<%= connect.options.livereload %>'
                },
                files: [
                    '<%= yeoman.app %>/{,*/}*.html',
                    '.tmp/styles/{,*/}*.css',
                    '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
                ]
            }
        },

        // The actual grunt server settings
        connect: {
            options: {
                port: 9000,
                // Change this to '0.0.0.0' to access the server from outside.
                hostname: 'localhost',
                livereload: 35729
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        '.tmp',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            test: {
                options: {
                    port: 9001,
                    base: [
                        '.tmp',
                        'test',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            dist: {
                options: {
                    base: '<%= yeoman.dist %>'
                }
            }
        },

        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                reporter: require('jshint-stylish')
            },
            all: [
                'Gruntfile.js',
                '<%= yeoman.app %>/scripts/{,*/}*.js'
            ],
            test: {
                options: {
                    jshintrc: 'test/.jshintrc'
                },
                src: ['test/spec/{,*/}*.js']
            }
        },

        // Empties folders to start fresh
        clean: {
            dist: {
                files: [
                    {
                        dot: true,
                        src: [
                            '.tmp',
                            '<%= yeoman.dist %>/*',
                            '!<%= yeoman.dist %>/.git*'
                        ]
                    }
                ]
            },
            server: '.tmp'
        },

        // Add vendor prefixed styles
        autoprefixer: {
            options: {
                browsers: ['last 1 version']
            },
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '.tmp/styles/',
                        src: '{,*/}*.css',
                        dest: '.tmp/styles/'
                    }
                ]
            }
        },

        // Automatically inject Bower components into the app
        bowerInstall: {
            app: {
                src: ['<%= yeoman.app %>/index.html'],
                ignorePath: '<%= yeoman.app %>/'
            },
            sass: {
                src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
                ignorePath: '<%= yeoman.app %>/bower_components/'
            }
        },

        // Compiles Sass to CSS and generates necessary files if requested
        compass: {
            options: {
                sassDir: '<%= yeoman.app %>/styles',
                cssDir: '.tmp/styles',
                generatedImagesDir: '.tmp/images/generated',
                imagesDir: '<%= yeoman.app %>/images',
                javascriptsDir: '<%= yeoman.app %>/scripts',
                fontsDir: '<%= yeoman.app %>/styles/fonts',
                importPath: '<%= yeoman.app %>/bower_components',
                httpImagesPath: '/images',
                httpGeneratedImagesPath: '/images/generated',
                httpFontsPath: '/styles/fonts',
                relativeAssets: false,
                assetCacheBuster: false,
                raw: 'Sass::Script::Number.precision = 10\n'
            },
            dist: {
                options: {
                    generatedImagesDir: '<%= yeoman.dist %>/images/generated'
                }
            },
            server: {
                options: {
                    debugInfo: true
                }
            }
        },

        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= yeoman.dist %>/scripts/{,*/}*.js',
                        '<%= yeoman.dist %>/styles/{,*/}*.css',
                        '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%= yeoman.dist %>/styles/fonts/*'
                    ]
                }
            }
        },

        // Reads HTML for usemin blocks to enable smart builds that automatically
        // concat, minify and revision files. Creates configurations in memory so
        // additional tasks can operate on them
        useminPrepare: {
            html: '<%= yeoman.app %>/index.html',
            options: {
                dest: '<%= yeoman.dist %>',
                flow: {
                    html: {
                        steps: {
                            js: ['concat', 'uglifyjs'],
                            css: ['cssmin']
                        },
                        post: {}
                    }
                }
            }
        },

        // Performs rewrites based on rev and the useminPrepare configuration
        usemin: {
            html: ['<%= yeoman.dist %>/{,*/}*.html'],
            css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
            options: {
                assetsDirs: ['<%= yeoman.dist %>']
            }
        },

        // The following *-min tasks produce minified files in the dist folder
        cssmin: {
            options: {
                root: '<%= yeoman.app %>'
            }
        },

        imagemin: {
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.app %>/images',
                        src: '{,*/}*.{png,jpg,jpeg,gif}',
                        dest: '<%= yeoman.dist %>/images'
                    }
                ]
            }
        },

        svgmin: {
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.app %>/images',
                        src: '{,*/}*.svg',
                        dest: '<%= yeoman.dist %>/images'
                    }
                ]
            }
        },

        htmlmin: {
            dist: {
                options: {
                    collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    removeCommentsFromCDATA: true,
                    removeOptionalTags: true
                },
                files: [
                    {
                        expand: true,
                        cwd: '<%= yeoman.dist %>',
                        src: ['*.html', 'views/{,*/}*.html'],
                        dest: '<%= yeoman.dist %>'
                    }
                ]
            }
        },

        // ngmin tries to make the code safe for minification automatically by
        // using the Angular long form for dependency injection. It doesn't work on
        // things like resolve or inject so those have to be done manually.
        ngmin: {
            dist: {
                files: [
                    {
                        expand: true,
                        cwd: '.tmp/concat/scripts',
                        src: '*.js',
                        dest: '.tmp/concat/scripts'
                    }
                ]
            }
        },

        // Replace Google CDN references
        cdnify: {
            dist: {
                html: ['<%= yeoman.dist %>/*.html']
            }
        },

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [
                    {
                        expand: true,
                        dot: true,
                        cwd: '<%= yeoman.app %>',
                        dest: '<%= yeoman.dist %>',
                        src: [
                            '*.{ico,png,txt}',
                            '.htaccess',
                            '*.html',
                            'views/{,*/}*.html',
                            'images/{,*/}*.{webp}',
                            'fonts/*'
                        ]
                    },
                    {
                        expand: true,
                        cwd: '.tmp/images',
                        dest: '<%= yeoman.dist %>/images',
                        src: ['generated/*']
                    }
                ]
            },
            styles: {
                expand: true,
                cwd: '<%= yeoman.app %>/styles',
                dest: '.tmp/styles/',
                src: '{,*/}*.css'
            }
        },

        // Run some tasks in parallel to speed up the build process
        concurrent: {
            server: [
                'compass:server'
            ],
            test: [
                'compass'
            ],
            dist: [
                'compass:dist',
                'imagemin',
                'svgmin'
            ]
        },

        // By default, your `index.html`'s <!-- Usemin block --> will take care of
        // minification. These next options are pre-configured if you do not wish
        // to use the Usemin blocks.
        // cssmin: {
        //   dist: {
        //     files: {
        //       '<%= yeoman.dist %>/styles/main.css': [
        //         '.tmp/styles/{,*/}*.css',
        //         '<%= yeoman.app %>/styles/{,*/}*.css'
        //       ]
        //     }
        //   }
        // },
        // uglify: {
        //   dist: {
        //     files: {
        //       '<%= yeoman.dist %>/scripts/scripts.js': [
        //         '<%= yeoman.dist %>/scripts/scripts.js'
        //       ]
        //     }
        //   }
        // },
        // concat: {
        //   dist: {}
        // },

        // Test settings
        karma: {
            unit: {
                configFile: 'karma.conf.js',
                singleRun: true
            }
        }
    });

    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'bowerInstall',
            'concurrent:server',
            'autoprefixer',
            'connect:livereload',
            'watch'
        ]);
    });

    grunt.registerTask('server', function (target) {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run(['serve:' + target]);
    });

    grunt.registerTask('test', [
        'clean:server',
        'concurrent:test',
        'autoprefixer',
        'connect:test',
        'karma'
    ]);

    grunt.registerTask('travis-test', [
        'clean:server',
        'connect:test',
        'karma'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'bowerInstall',
        'useminPrepare',
        'concurrent:dist',
        'autoprefixer',
        'concat',
        'ngmin',
        'copy:dist',
        'cdnify',
        'cssmin',
        'uglify',
        'rev',
        'usemin',
        'htmlmin'
    ]);

    grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
    ]);
};
<|endoftext|>


<commit_before>$(document).ready(function() {
  // This is called after the document has loaded in its entirety
  // This guarantees that any elements we bind to will exist on the page
  // when we try to bind to them

  // See: http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
  $('.comment-form').on('submit', function(event){
    event.preventDefault();

    var url = $(this).attr('action');
    var data = $(this).serialize();

    var request = $.ajax({
              url: url,
              method: 'POST',
              data: data
    });

    request.done(function(response){
      $('.comments ul').append(
        $('
' + response.content + 'Edit<form class="comment-delete" action="/comments/'+response.id+'/delete" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="Delete"></form>')
      );
      $('.comment-form textarea').val('');
    });
  });

  $('.comments').on('click', '.comment-edit', function(event){
    event.preventDefault();

    if ($('.comments').find('#dynaform').attr('action')){
      formText = $('#dynaform input[type=text]').val();
      id = $('#dynaform').parent().attr('id')

      $('#dynaform').replaceWith(formText + ' Edit<form class="comment-delete" action="/comments/'+id+'/delete" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="Delete"></form>');
    };

    $listItem = $(this).parent();
    commentId = $listItem.attr('id')
    commentText = $listItem
                    .clone()
                    .children()
                    .remove()
                    .end()
                    .text()
                    .trim();

    $listItem.html('<form id="dynaform" action="/comments/'+commentId+'/edit" method="post"><input type="hidden" name="_method" value="put" ><input name="content" type="text" value="'+commentText+'"><input type="submit"></form>');

    $listItem.on('submit', '#dynaform', function(event){
      event.preventDefault();

      id = $(this).parent().attr('id')

      url = $(this).attr('action');
      data = $(this).serialize();

      request = $.ajax({
              url: url,
              method: 'put',
              data: data
      });

      request.done(function(text){
        console.log(text);
        $listItem.html(text + ' Edit<form class="comment-delete" action="/comments/'+id+'/delete" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="Delete"></form>');
      });
    });
  });

  $('.comments').on('click', '.comment-delete', function(event){
    event.preventDefault();

    url = $(this).attr('action')

    request = $.ajax({
      url: url,
      method: 'delete'
    });

    request.done(function(id){
      $('.comments #'+id).remove();
    });
  });

});
<commit_msg>Fix up spacing on edit links<commit_after>$(document).ready(function() {
  // This is called after the document has loaded in its entirety
  // This guarantees that any elements we bind to will exist on the page
  // when we try to bind to them

  // See: http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
  $('.comment-form').on('submit', function(event){
    event.preventDefault();

    var url = $(this).attr('action');
    var data = $(this).serialize();

    var request = $.ajax({
              url: url,
              method: 'POST',
              data: data
    });

    request.done(function(response){
      $('.comments ul').append(
        $('
' + response.content + ' Edit<form class="comment-delete" action="/comments/'+response.id+'/delete" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="Delete"></form>')
      );
      $('.comment-form textarea').val('');
    });
  });

  $('.comments').on('click', '.comment-edit', function(event){
    event.preventDefault();

    if ($('.comments').find('#dynaform').attr('action')){
      formText = $('#dynaform input[type=text]').val();
      id = $('#dynaform').parent().attr('id')

      $('#dynaform').replaceWith(formText + ' Edit<form class="comment-delete" action="/comments/'+id+'/delete" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="Delete"></form>');
    };

    $listItem = $(this).parent();
    commentId = $listItem.attr('id')
    commentText = $listItem
                    .clone()
                    .children()
                    .remove()
                    .end()
                    .text()
                    .trim();

    $listItem.html('<form id="dynaform" action="/comments/'+commentId+'/edit" method="post"><input type="hidden" name="_method" value="put" ><input name="content" type="text" value="'+commentText+'"><input type="submit"></form>');

    $listItem.on('submit', '#dynaform', function(event){
      event.preventDefault();

      id = $(this).parent().attr('id')

      url = $(this).attr('action');
      data = $(this).serialize();

      request = $.ajax({
              url: url,
              method: 'put',
              data: data
      });

      request.done(function(text){
        console.log(text);
        $listItem.html(text + ' Edit<form class="comment-delete" action="/comments/'+id+'/delete" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="Delete"></form>');
      });
    });
  });

  $('.comments').on('click', '.comment-delete', function(event){
    event.preventDefault();

    url = $(this).attr('action')

    request = $.ajax({
      url: url,
      method: 'delete'
    });

    request.done(function(id){
      $('.comments #'+id).remove();
    });
  });

});
<|endoftext|>


<commit_before>angular.module('starter.controllers', [])

.controller('AppCtrl', function($scope, $translate) {
    storage = window.localStorage;
    var settings = storage.getItem("settings");
    $scope.settings = (settings !== null) ? JSON.parse(settings) : {}

    // Set defaults
    $scope.settings.lang = typeof $scope.settings.lang !== 'undefined' ? $scope.settings.lang : {code: 'en'};

    $translate.use($scope.settings.lang.code);

    $scope.duration = function(dur, type){
        return moment.duration(dur, type).humanize();
    }
})

.controller('TrackCtrl', function($scope, trackRepository){
    moment.lang($scope.settings.lang.code);
    // Start count function
    $scope.startCount = function(){
        if(!$scope.track.pause){
            $scope.track.startTime = Date.now();
            $scope.track.id = undefined;
        }
        $scope.track.pause = false;
        $scope.clock.start();
    }

    $scope.pauseCount = function(callback){
        $scope.clock.pause();
        $scope.track.endTime = Date.now();
        $scope.track.pause = true;
        $scope.track.timeInterval = $scope.clock.getTime();
        if($scope.track.id === undefined){
            trackRepository.save($scope.track, callback);
            return;
        }

        trackRepository.update($scope.track, callback);

    }

    $scope.stopCount = function(){
        $scope.clock.pause();
        $scope.track.endTime = Date.now();
        $scope.track.pause = false;
        $scope.track.timeInterval = $scope.clock.getTime();
        $scope.clock.stop();

        if($scope.track.id === undefined){
            trackRepository.save($scope.track);

        }else{
            trackRepository.update($scope.track);
        }

        $scope.last = $scope.track;
    }

    $scope.selectBreast = function(breast){
        $scope.track.breast = breast.charAt(1).toUpperCase();
        $scope.bbc = $scope.blc = $scope.brc = "button button-stable";
        $scope[breast] = "button button-balanced";
    }

    $scope.goBackground = function(){
        console.log("go background");
        if(!($scope.clock.getTime() > 0))
            console.log("go background: no timer running exit.");
            return;
        if(!$scope.track.pause){
            console.log("go background: timer paused, setting pause status.");
            $scope.pauseCount(function(){
                $scope.track.pause = false;
                storage.setItem("timer", JSON.stringify($scope.track));
            });
            return;
        }
        console.log("go background: timer running storing status.");
        storage.setItem("timer", JSON.stringify($scope.track));
    }

    restoreBackground = function(){
        console.log("restoring background");
        timer = storage.getItem("timer");
        storage.removeItem("timer");
        $scope.track = JSON.parse(timer);
        currtiming = $scope.track.timeInterval*1000;
        currdate = new Date();

        if(!$scope.track.pause){
            currtiming += (currdate.getTime() - $scope.track.endTime);
        }

        if('clock' in $scope){
            $scope.clock.setTime(currtiming, true);
        }else{
            $scope.clock = $('.your-clock').tinytimer(currtiming);
        }

        if(!$scope.track.pause){
            console.log("restoring background: start clock");
            $scope.clock.start();
        }

        getLastTrack(1);
    }

    getLastTrack = function(row){
        row = typeof row !== 'undefined' ? row : 0;
        trackRepository.getLastTrack($scope.last, function(){
            switch ($scope.last.breast){
                case 'L':
                    $scope.selectBreast('blc');
                    break;
                case 'R':
                    $scope.selectBreast('brc');
                    break;
                case 'B':
                    $scope.selectBreast('bbc');
                    break;
                default:
                    break;
            }

        },
        row);
    }

    // Listen view change event and store progress.
    $scope.$on('$locationChangeStart', function(event) {
        $scope.goBackground();
        document.removeEventListener("pause", $scope.goBackground, false);
        document.removeEventListener("resume", restoreBackground, false);
    });

    document.addEventListener("pause", $scope.goBackground, false);
    document.addEventListener("resume", restoreBackground, false);

    $scope.last = {};

    $scope.bbc = $scope.blc = $scope.brc = "button button-stable";
    var testtimer = storage.getItem("timer");
    console.log(testtimer, testtimmer === null);
    if(storage.getItem("timer")){
        restoreBackground();
    }
    else{
        // Init timer.
        $scope.clock = $('.your-clock').tinytimer(0, true);

        // track object
        $scope.track = {};
        $scope.track.pause = false;
        $scope.track.breast = "L";
        $scope.track.id = undefined;
        getLastTrack();
    }

})

.controller('HistoryCtrl', function($scope, trackRepository){
    moment.lang($scope.settings.lang.code);
    $scope.limit = 0;
    $scope.tracks = [];
    $scope.moreDataCanBeLoaded = true;
    $scope.getItems = function(increase){
        $scope.limit += increase;
        $scope.days = [];
        $scope.tracks = [];
        trackRepository.getTracksByDay($scope.limit, $scope.tracks, function(){
            var lent = $scope.tracks.length, lend = undefined, i;
            for(i=0;i<lent;i++){
                if(lend == undefined){
                    $scope.days[0] = [];
                    $scope.days[0].push($scope.tracks[i]);
                    lend=0;
                    continue;
                }

                tdate = new Date($scope.tracks[i].endTime);
                tdates = tdate.getDate()+"-"+tdate.getMonth()+"-"+tdate.getFullYear();
                ddate = new Date($scope.days[lend][0].endTime);
                ddates = ddate.getDate()+"-"+ddate.getMonth()+"-"+ddate.getFullYear();

                if(tdates.localeCompare(ddates) === 0){
                    $scope.days[lend].push($scope.tracks[i]);
                    continue;
                }
                lend+=1;
                $scope.days[lend] = [];
                $scope.days[lend].push($scope.tracks[i]);
            }

            $scope.$broadcast('scroll.infiniteScrollComplete');
        });
    }

    $scope.getTotalFeed = function(arr){
        len = arr.length;
        total = 0;
        for(i=0;i<len;i++)
            total+=arr[i].timeInterval;

        return moment.duration(total, 'seconds').humanize();
    }

    $scope.moreData = function(){
        return $scope.moreDataCanBeLoaded;
    }

    // Get 2 days.
    $scope.getItems(2);

})

.controller('SettingsCtrl', function($rootScope, $scope, $translate){
    $scope.languages = [
        {code: 'es', text: 'lang_es'},
        {code: 'en', text: 'lang_en'},
        {code: 'ca', text: 'lang_ca'}
    ];

    $scope.setLanguage = function(){
        storage.setItem("settings", JSON.stringify($scope.settings));
        $translate.use($scope.settings.lang.code)
    }
})<commit_msg>Fixed resume/pause event handling to restore count<commit_after>angular.module('starter.controllers', [])

.controller('AppCtrl', function($scope, $translate) {
    storage = window.localStorage;
    var settings = storage.getItem("settings");
    $scope.settings = (settings !== null) ? JSON.parse(settings) : {}

    // Set defaults
    $scope.settings.lang = typeof $scope.settings.lang !== 'undefined' ? $scope.settings.lang : {code: 'en'};

    $translate.use($scope.settings.lang.code);

    $scope.duration = function(dur, type){
        return moment.duration(dur, type).humanize();
    }
})

.controller('TrackCtrl', function($scope, trackRepository){
    moment.lang($scope.settings.lang.code);
    // Start count function
    $scope.startCount = function(){
        if(!$scope.track.pause){
            $scope.track.startTime = Date.now();
            $scope.track.id = undefined;
        }
        $scope.track.pause = false;
        $scope.clock.start();
    }

    $scope.pauseCount = function(callback){
        $scope.clock.pause();
        $scope.track.endTime = Date.now();
        $scope.track.pause = true;
        $scope.track.timeInterval = $scope.clock.getTime();
        if($scope.track.id === undefined){
            trackRepository.save($scope.track, callback);
            return;
        }

        trackRepository.update($scope.track, callback);

    }

    $scope.stopCount = function(){
        $scope.clock.pause();
        $scope.track.endTime = Date.now();
        $scope.track.pause = false;
        $scope.track.timeInterval = $scope.clock.getTime();
        $scope.clock.stop();

        if($scope.track.id === undefined){
            trackRepository.save($scope.track);

        }else{
            trackRepository.update($scope.track);
        }

        $scope.last = $scope.track;
    }

    $scope.selectBreast = function(breast){
        $scope.track.breast = breast.charAt(1).toUpperCase();
        $scope.bbc = $scope.blc = $scope.brc = "button button-stable";
        $scope[breast] = "button button-balanced";
    }

    $scope.goBackground = function(){
        if(!($scope.clock.getTime() > 0)){
            return;
        }

        if(!$scope.track.pause){
            $scope.pauseCount(function(){
                $scope.track.pause = false;
                storage.setItem("timer", JSON.stringify($scope.track));
            });
            return;
        }

        storage.setItem("timer", JSON.stringify($scope.track));
    }

    restoreBackground = function(){
        timer = storage.getItem("timer");
        storage.removeItem("timer");
        if(timer === null)
            return;

        $scope.track = JSON.parse(timer);
        currtiming = $scope.track.timeInterval*1000;
        currdate = new Date();

        if(!$scope.track.pause){
            currtiming += (currdate.getTime() - $scope.track.endTime);
        }

        if('clock' in $scope){
            $scope.clock.setTime(currtiming, true);
        }else{
            $scope.clock = $('.your-clock').tinytimer(currtiming);
        }

        if(!$scope.track.pause){
            $scope.clock.start();
        }

        getLastTrack(1);
    }

    getLastTrack = function(row){
        row = typeof row !== 'undefined' ? row : 0;
        trackRepository.getLastTrack($scope.last, function(){
            switch ($scope.last.breast){
                case 'L':
                    $scope.selectBreast('blc');
                    break;
                case 'R':
                    $scope.selectBreast('brc');
                    break;
                case 'B':
                    $scope.selectBreast('bbc');
                    break;
                default:
                    break;
            }

        },
        row);
    }

    // Listen view change event and store progress.
    $scope.$on('$locationChangeStart', function(event) {
        $scope.goBackground();
        document.removeEventListener("pause", $scope.goBackground, false);
        document.removeEventListener("resume", restoreBackground, false);
    });

    document.addEventListener("pause", $scope.goBackground, false);
    document.addEventListener("resume", restoreBackground, false);

    $scope.last = {};

    $scope.bbc = $scope.blc = $scope.brc = "button button-stable";
    var testtimer = storage.getItem("timer");
    if(storage.getItem("timer")){
        restoreBackground();
    }
    else{
        // Init timer.
        $scope.clock = $('.your-clock').tinytimer(0, true);

        // track object
        $scope.track = {};
        $scope.track.pause = false;
        $scope.track.breast = "L";
        $scope.track.id = undefined;
        getLastTrack();
    }

})

.controller('HistoryCtrl', function($scope, trackRepository){
    moment.lang($scope.settings.lang.code);
    $scope.limit = 0;
    $scope.tracks = [];
    $scope.moreDataCanBeLoaded = true;
    $scope.getItems = function(increase){
        $scope.limit += increase;
        $scope.days = [];
        $scope.tracks = [];
        trackRepository.getTracksByDay($scope.limit, $scope.tracks, function(){
            var lent = $scope.tracks.length, lend = undefined, i;
            for(i=0;i<lent;i++){
                if(lend == undefined){
                    $scope.days[0] = [];
                    $scope.days[0].push($scope.tracks[i]);
                    lend=0;
                    continue;
                }

                tdate = new Date($scope.tracks[i].endTime);
                tdates = tdate.getDate()+"-"+tdate.getMonth()+"-"+tdate.getFullYear();
                ddate = new Date($scope.days[lend][0].endTime);
                ddates = ddate.getDate()+"-"+ddate.getMonth()+"-"+ddate.getFullYear();

                if(tdates.localeCompare(ddates) === 0){
                    $scope.days[lend].push($scope.tracks[i]);
                    continue;
                }
                lend+=1;
                $scope.days[lend] = [];
                $scope.days[lend].push($scope.tracks[i]);
            }

            $scope.$broadcast('scroll.infiniteScrollComplete');
        });
    }

    $scope.getTotalFeed = function(arr){
        len = arr.length;
        total = 0;
        for(i=0;i<len;i++)
            total+=arr[i].timeInterval;

        return moment.duration(total, 'seconds').humanize();
    }

    $scope.moreData = function(){
        return $scope.moreDataCanBeLoaded;
    }

    // Get 2 days.
    $scope.getItems(2);

})

.controller('SettingsCtrl', function($rootScope, $scope, $translate){
    $scope.languages = [
        {code: 'es', text: 'lang_es'},
        {code: 'en', text: 'lang_en'},
        {code: 'ca', text: 'lang_ca'}
    ];

    $scope.setLanguage = function(){
        storage.setItem("settings", JSON.stringify($scope.settings));
        $translate.use($scope.settings.lang.code)
    }
})<|endoftext|>


<commit_before>import React from 'react';
import { storiesOf } from '@storybook/react';
import { checkA11y } from 'storybook-addon-a11y';
import { withInfo } from '@storybook/addon-info';
import { Store, State } from '@sambego/storybook-state';
import styles from '@sambego/storybook-styles';
import { Avatar, AvatarStack, Box, Bullet, Counter, TextBody, Tooltip } from '../components';
import { baseStyles, centerStyles } from '../.storybook/styles';

import Image1 from '../static/avatars/1.png';
import Image2 from '../static/avatars/2.png';
import Image3 from '../static/avatars/3.png';
import Image4 from '../static/avatars/4.png';
import Image5 from '../static/avatars/5.png';
import Image6 from '../static/avatars/6.png';
import Image7 from '../static/avatars/7.png';
import Image8 from '../static/avatars/8.png';

const avatars = [
  { image: Image1, count: 21, color: 'ruby', maxCount: 20 },
  { image: Image2, count: 15, color: 'neutral', inactive: true },
  { image: Image3, count: 5, color: 'neutral' },
  { image: Image4, count: 3, color: 'ruby' },
  { image: Image5, count: 0, color: 'ruby' },
  { image: Image6, count: 4, color: 'ruby' },
  { image: Image7, count: 5, color: 'neutral', inactive: true },
  { image: Image8, count: 2, color: 'neutral', inactive: true },
];

const store = new Store({
  displayMax: 5,
});

const TooltippedAvatar = Tooltip(Avatar);

const handleOnOverflowClick = () => {
  store.set({ displayMax: 0 });
};

storiesOf('Avatars', module)
  .addDecorator((story, context) => withInfo('common info')(story)(context))
  .addDecorator(checkA11y)
  .add('sizes', () => (

      <Avatar image={avatars[0].image} size="tiny" marginHorizontal={4} />
      <Avatar image={avatars[0].image} size="small" marginHorizontal={4} />
      <Avatar image={avatars[0].image} size="medium" marginHorizontal={4} />

  ))
  .add('with bullet', () => (

      <Avatar
        image={avatars[0].image}
        size="small"
        marginHorizontal={4}
      >
        <Bullet color="ruby" size="small" />
      </Avatar>
      <Avatar
        image={avatars[0].image}
        marginHorizontal={4}
      >
        <Bullet color="ruby" />
      </Avatar>

  ))
  .add('with counter', () => (

      <Avatar
        image={avatars[0].image}
        size="small"
        marginHorizontal={4}
      >
        <Counter color="ruby" count={avatars[0].count} size="small" />
      </Avatar>
      <Avatar
        image={avatars[0].image}
        marginHorizontal={4}
      >
        <Counter color="ruby" count={avatars[0].count} maxCount={avatars[0].maxCount}/>
      </Avatar>

  ))
  .add('stacked horizontal', () => (

      <State store={store}>
        <AvatarStack
          direction="horizontal"
          displayMax={5}
          inverse={false}
          onOverflowClick={handleOnOverflowClick}
          size="medium"
        >
          {avatars.map(({ image, count, color, inactive, maxCount }, index) => (
            <Avatar
              key={index}
              image={image}
              size="medium"
            />
          ))}
        </AvatarStack>
      </State>

  ))
  .add('stacked vertical', () => (

      <State store={store}>
        <AvatarStack
          direction="vertical"
          displayMax={3}
          inverse={false}
          onOverflowClick={handleOnOverflowClick}
          size="medium"
          marginTop={8}
        >
          {avatars.map(({ image, color, inactive }, index) => (
            <Avatar
              key={index}
              image={image}
              size="medium"
            />
          ))}
        </AvatarStack>
      </State>

  ))
  .add('with tooltip', () => (

      <TooltippedAvatar
        image={avatars[0].image}
        size="tiny"
        tooltip={<TextBody>I am the tooltip</TextBody>}
      />

  ));
<commit_msg>Avatar: remove centerStyles because we moved this to a higher level<commit_after>import React from 'react';
import { storiesOf } from '@storybook/react';
import { checkA11y } from 'storybook-addon-a11y';
import { withInfo } from '@storybook/addon-info';
import { Store, State } from '@sambego/storybook-state';
import { Avatar, AvatarStack, Box, Bullet, Counter, TextBody, Tooltip } from '../components';

import Image1 from '../static/avatars/1.png';
import Image2 from '../static/avatars/2.png';
import Image3 from '../static/avatars/3.png';
import Image4 from '../static/avatars/4.png';
import Image5 from '../static/avatars/5.png';
import Image6 from '../static/avatars/6.png';
import Image7 from '../static/avatars/7.png';
import Image8 from '../static/avatars/8.png';

const avatars = [
  { image: Image1, count: 21, color: 'ruby', maxCount: 20 },
  { image: Image2, count: 15, color: 'neutral', inactive: true },
  { image: Image3, count: 5, color: 'neutral' },
  { image: Image4, count: 3, color: 'ruby' },
  { image: Image5, count: 0, color: 'ruby' },
  { image: Image6, count: 4, color: 'ruby' },
  { image: Image7, count: 5, color: 'neutral', inactive: true },
  { image: Image8, count: 2, color: 'neutral', inactive: true },
];

const store = new Store({
  displayMax: 5,
});

const TooltippedAvatar = Tooltip(Avatar);

const handleOnOverflowClick = () => {
  store.set({ displayMax: 0 });
};

storiesOf('Avatars', module)
  .addDecorator((story, context) => withInfo('common info')(story)(context))
  .addDecorator(checkA11y)
  .add('sizes', () => (

      <Avatar image={avatars[0].image} size="tiny" marginHorizontal={4} />
      <Avatar image={avatars[0].image} size="small" marginHorizontal={4} />
      <Avatar image={avatars[0].image} size="medium" marginHorizontal={4} />

  ))
  .add('with bullet', () => (

      <Avatar
        image={avatars[0].image}
        size="small"
        marginHorizontal={4}
      >
        <Bullet color="ruby" size="small" />
      </Avatar>
      <Avatar
        image={avatars[0].image}
        marginHorizontal={4}
      >
        <Bullet color="ruby" />
      </Avatar>

  ))
  .add('with counter', () => (

      <Avatar
        image={avatars[0].image}
        size="small"
        marginHorizontal={4}
      >
        <Counter color="ruby" count={avatars[0].count} size="small" />
      </Avatar>
      <Avatar
        image={avatars[0].image}
        marginHorizontal={4}
      >
        <Counter color="ruby" count={avatars[0].count} maxCount={avatars[0].maxCount}/>
      </Avatar>

  ))
  .add('stacked horizontal', () => (

      <State store={store}>
        <AvatarStack
          direction="horizontal"
          displayMax={5}
          inverse={false}
          onOverflowClick={handleOnOverflowClick}
          size="medium"
        >
          {avatars.map(({ image, count, color, inactive, maxCount }, index) => (
            <Avatar
              key={index}
              image={image}
              size="medium"
            />
          ))}
        </AvatarStack>
      </State>

  ))
  .add('stacked vertical', () => (

      <State store={store}>
        <AvatarStack
          direction="vertical"
          displayMax={3}
          inverse={false}
          onOverflowClick={handleOnOverflowClick}
          size="medium"
          marginTop={8}
        >
          {avatars.map(({ image, color, inactive }, index) => (
            <Avatar
              key={index}
              image={image}
              size="medium"
            />
          ))}
        </AvatarStack>
      </State>

  ))
  .add('with tooltip', () => (

      <TooltippedAvatar
        image={avatars[0].image}
        size="tiny"
        tooltip={<TextBody>I am the tooltip</TextBody>}
      />

  ));
<|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'),
    xcode         = require('xcode'),
    util          = require('../util'),
    events        = require('../events'),
    shell         = require('shelljs'),
    child_process = require('child_process'),
    plist         = require('plist'),
    semver        = require('semver'),
    Q             = require('q'),
    config_parser = require('../config_parser'),
    config        = require('../config');

var MIN_XCODE_VERSION = '>=4.5.x';

var default_prefs = {
    "KeyboardDisplayRequiresUserAction":"true",
    "SuppressesIncrementalRendering":"false",
    "UIWebViewBounce":"true",
    "TopActivityIndicator":"gray",
    "EnableLocation":"false",
    "EnableViewportScale":"false",
    "AutoHideSplashScreen":"true",
    "ShowSplashScreenSpinner":"true",
    "MediaPlaybackRequiresUserAction":"false",
    "AllowInlineMediaPlayback":"false",
    "OpenAllWhitelistURLsInWebView":"false",
    "BackupWebStorage":"cloud",
    "UsePlayerMode":"true" //TODO:To be removed!
};

module.exports = function ios_parser(project) {
    try {
        var xcodeproj_dir = fs.readdirSync(project).filter(function(e) { return e.match(/\.xcodeproj$/i); })[0];
        if (!xcodeproj_dir) throw new Error('The provided path "' + project + '" is not a xFace iOS project.');
        this.xcodeproj = path.join(project, xcodeproj_dir);
        this.originalName = this.xcodeproj.substring(this.xcodeproj.lastIndexOf(path.sep)+1, this.xcodeproj.indexOf('.xcodeproj'));
        this.cordovaproj = path.join(project, this.originalName);
    } catch(e) {
        throw new Error('The provided path is not a xFace iOS project.');
    }
    this.path = project;
    this.pbxproj = path.join(this.xcodeproj, 'project.pbxproj');
    this.config_path = path.join(this.cordovaproj, 'config.xml');
    this.config = new util.config_parser(this.config_path);
};

// Returns a promise.
module.exports.check_requirements = function(project_root) {
    events.emit('log', 'Checking iOS requirements...');
    // Check xcode + version.
    var command = 'xcodebuild -version';
    events.emit('verbose', 'Running "' + command + '" (output to follow)');
    var d = Q.defer();
    child_process.exec(command, function(err, output, stderr) {
        events.emit('verbose', output+stderr);
        if (err) {
            d.reject(new Error('Xcode is (probably) not installed, specifically the command `xcodebuild` is unavailable or erroring out. Output of `'+command+'` is: ' + output + stderr));
        } else {
            var xc_version = output.split('\n')[0].split(' ')[1];
            if(xc_version.split('.').length === 2){
                xc_version += '.0';
            }
            if (!semver.satisfies(xc_version, MIN_XCODE_VERSION)) {
                d.reject(new Error('Xcode version installed is too old. Minimum: ' + MIN_XCODE_VERSION + ', yours: ' + xc_version));
            } else d.resolve();
        }
    });
    return d.promise;
};

module.exports.prototype = {
    // Returns a promise.
    update_from_config:function(config) {
        if (config instanceof config_parser) {
        } else {
            return Q.reject(new Error('update_from_config requires a config_parser object'));
        }
        var name = config.name();
        var pkg = config.packageName();
        var version = config.version();

        // Update package id (bundle id)
        var plistFile = path.join(this.cordovaproj, this.originalName + '-Info.plist');
        var infoPlist = plist.parseFileSync(plistFile);
        infoPlist['CFBundleIdentifier'] = pkg;

        // Update version (bundle version)
        infoPlist['CFBundleVersion'] = version;
        var info_contents = plist.build(infoPlist);
        info_contents = info_contents.replace(/<string>[\s\r\n]*<\/string>/g,'<string></string>');
        fs.writeFileSync(plistFile, info_contents, 'utf-8');
        events.emit('verbose', 'Wrote out iOS Bundle Identifier to "' + pkg + '"');
        events.emit('verbose', 'Wrote out iOS Bundle Version to "' + version + '"');

        // Update whitelist
        var self = this;
        this.config.access.remove();
        config.access.get().forEach(function(uri) {
            self.config.access.add(uri);
        });

        // Update content (start page)
        this.config.content(config.content());

        // Update preferences
        this.config.preference.remove();
        var prefs = config.preference.get();
        // write out defaults, unless user has specifically overrode it
        for (var p in default_prefs) if (default_prefs.hasOwnProperty(p)) {
            var override = prefs.filter(function(pref) { return pref.name == p; });
            var value = default_prefs[p];
            if (override.length) {
                // override exists
                value = override[0].value;
                // remove from prefs list so we dont write it out again below
                prefs = prefs.filter(function(pref) { return pref.name != p });
            }
            this.config.preference.add({
                name:p,
                value:value
            });
        }
        prefs.forEach(function(pref) {
            self.config.preference.add({
                name:pref.name,
                value:pref.value
            });
        });

        if (name != this.originalName) {
            // Update product name inside pbxproj file
            var proj = new xcode.project(this.pbxproj);
            var parser = this;
            var d = Q.defer();
            proj.parse(function(err,hash) {
                if (err) {
                    d.reject(new Error('An error occured during parsing of project.pbxproj. Start weeping. Output: ' + err));
                } else {
                    proj.updateProductName(name);
                    fs.writeFileSync(parser.pbxproj, proj.writeSync(), 'utf-8');
                    // Move the xcodeproj and other name-based dirs over.
                    shell.mv(path.join(parser.cordovaproj, parser.originalName + '-Info.plist'), path.join(parser.cordovaproj, name + '-Info.plist'));
                    shell.mv(path.join(parser.cordovaproj, parser.originalName + '-Prefix.pch'), path.join(parser.cordovaproj, name + '-Prefix.pch'));
                    shell.mv(parser.xcodeproj, path.join(parser.path, name + '.xcodeproj'));
                    shell.mv(parser.cordovaproj, path.join(parser.path, name));
                    // Update self object with new paths
                    var old_name = parser.originalName;
                    parser = new module.exports(parser.path);
                    // Hack this shi*t
                    var pbx_contents = fs.readFileSync(parser.pbxproj, 'utf-8');
                    pbx_contents = pbx_contents.split(old_name).join(name);
                    fs.writeFileSync(parser.pbxproj, pbx_contents, 'utf-8');
                    events.emit('verbose', 'Wrote out iOS Product Name and updated XCode project file names from "'+old_name+'" to "' + name + '".');
                    d.resolve();
                }
            });
            return d.promise;
        } else {
            events.emit('verbose', 'iOS Product Name has not changed (still "' + this.originalName + '")');
            return Q();
        }
    },

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

    staging_dir: function() {
        return path.join(this.path, '.staging', 'www');
    },

    config_xml:function(){
        return this.config_path;
    },

    update_www:function() {
        var projectRoot = util.isxFace(this.path);
        var www = util.projectWww(projectRoot);
        var project_www = this.www_dir();

        // remove the stock www folder
        shell.rm('-rf', project_www);

        // copy over project www assets
        shell.cp('-rf', www, this.path);

        // write out proper cordova.js
        var custom_path = config.has_custom_path(projectRoot, 'ios');
        var lib_path = util.getDefaultPlatformLibPath(projectRoot, 'ios');
        if (custom_path) lib_path = custom_path;
        shell.cp('-f', path.join(lib_path, 'xFaceLib', 'xFaceLib', 'xface.js'), path.join(project_www, 'xface.js'));
    },

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

    // update the overrides folder into the www folder
    update_staging:function() {
        var projectRoot = util.isxFace(this.path);
        if (fs.existsSync(this.staging_dir())) {
            var staging = path.join(this.staging_dir(), '*');
            shell.cp('-rf', staging, this.www_dir());
        }
    },

    // Returns a promise.
    update_project:function(cfg) {
        var self = this;
        return this.update_from_config(cfg)
        .then(function() {
            self.update_www();
            self.update_overrides();
            self.update_staging();
            util.deleteSvnFolders(self.www_dir());
        });
    }
};
<commit_msg>在默认应用目录由www->xface3/helloxface之后，修改ios平台拷贝应用及js的逻辑<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'),
    xcode         = require('xcode'),
    util          = require('../util'),
    events        = require('../events'),
    shell         = require('shelljs'),
    child_process = require('child_process'),
    plist         = require('plist'),
    semver        = require('semver'),
    Q             = require('q'),
    config_parser = require('../config_parser'),
    config        = require('../config');

var MIN_XCODE_VERSION = '>=4.5.x';

var default_prefs = {
    "KeyboardDisplayRequiresUserAction":"true",
    "SuppressesIncrementalRendering":"false",
    "UIWebViewBounce":"true",
    "TopActivityIndicator":"gray",
    "EnableLocation":"false",
    "EnableViewportScale":"false",
    "AutoHideSplashScreen":"true",
    "ShowSplashScreenSpinner":"true",
    "MediaPlaybackRequiresUserAction":"false",
    "AllowInlineMediaPlayback":"false",
    "OpenAllWhitelistURLsInWebView":"false",
    "BackupWebStorage":"cloud",
    "UsePlayerMode":"true" //TODO:To be removed!
};

module.exports = function ios_parser(project) {
    try {
        var xcodeproj_dir = fs.readdirSync(project).filter(function(e) { return e.match(/\.xcodeproj$/i); })[0];
        if (!xcodeproj_dir) throw new Error('The provided path "' + project + '" is not a xFace iOS project.');
        this.xcodeproj = path.join(project, xcodeproj_dir);
        this.originalName = this.xcodeproj.substring(this.xcodeproj.lastIndexOf(path.sep)+1, this.xcodeproj.indexOf('.xcodeproj'));
        this.cordovaproj = path.join(project, this.originalName);
    } catch(e) {
        throw new Error('The provided path is not a xFace iOS project.');
    }
    this.path = project;
    this.pbxproj = path.join(this.xcodeproj, 'project.pbxproj');
    this.config_path = path.join(this.cordovaproj, 'config.xml');
    this.config = new util.config_parser(this.config_path);
};

// Returns a promise.
module.exports.check_requirements = function(project_root) {
    events.emit('log', 'Checking iOS requirements...');
    // Check xcode + version.
    var command = 'xcodebuild -version';
    events.emit('verbose', 'Running "' + command + '" (output to follow)');
    var d = Q.defer();
    child_process.exec(command, function(err, output, stderr) {
        events.emit('verbose', output+stderr);
        if (err) {
            d.reject(new Error('Xcode is (probably) not installed, specifically the command `xcodebuild` is unavailable or erroring out. Output of `'+command+'` is: ' + output + stderr));
        } else {
            var xc_version = output.split('\n')[0].split(' ')[1];
            if(xc_version.split('.').length === 2){
                xc_version += '.0';
            }
            if (!semver.satisfies(xc_version, MIN_XCODE_VERSION)) {
                d.reject(new Error('Xcode version installed is too old. Minimum: ' + MIN_XCODE_VERSION + ', yours: ' + xc_version));
            } else d.resolve();
        }
    });
    return d.promise;
};

module.exports.prototype = {
    // Returns a promise.
    update_from_config:function(config) {
        if (config instanceof config_parser) {
        } else {
            return Q.reject(new Error('update_from_config requires a config_parser object'));
        }
        var name = config.name();
        var pkg = config.packageName();
        var version = config.version();

        // Update package id (bundle id)
        var plistFile = path.join(this.cordovaproj, this.originalName + '-Info.plist');
        var infoPlist = plist.parseFileSync(plistFile);
        infoPlist['CFBundleIdentifier'] = pkg;

        // Update version (bundle version)
        infoPlist['CFBundleVersion'] = version;
        var info_contents = plist.build(infoPlist);
        info_contents = info_contents.replace(/<string>[\s\r\n]*<\/string>/g,'<string></string>');
        fs.writeFileSync(plistFile, info_contents, 'utf-8');
        events.emit('verbose', 'Wrote out iOS Bundle Identifier to "' + pkg + '"');
        events.emit('verbose', 'Wrote out iOS Bundle Version to "' + version + '"');

        // Update whitelist
        var self = this;
        this.config.access.remove();
        config.access.get().forEach(function(uri) {
            self.config.access.add(uri);
        });

        // Update content (start page)
        this.config.content(config.content());

        // Update preferences
        this.config.preference.remove();
        var prefs = config.preference.get();
        // write out defaults, unless user has specifically overrode it
        for (var p in default_prefs) if (default_prefs.hasOwnProperty(p)) {
            var override = prefs.filter(function(pref) { return pref.name == p; });
            var value = default_prefs[p];
            if (override.length) {
                // override exists
                value = override[0].value;
                // remove from prefs list so we dont write it out again below
                prefs = prefs.filter(function(pref) { return pref.name != p });
            }
            this.config.preference.add({
                name:p,
                value:value
            });
        }
        prefs.forEach(function(pref) {
            self.config.preference.add({
                name:pref.name,
                value:pref.value
            });
        });

        if (name != this.originalName) {
            // Update product name inside pbxproj file
            var proj = new xcode.project(this.pbxproj);
            var parser = this;
            var d = Q.defer();
            proj.parse(function(err,hash) {
                if (err) {
                    d.reject(new Error('An error occured during parsing of project.pbxproj. Start weeping. Output: ' + err));
                } else {
                    proj.updateProductName(name);
                    fs.writeFileSync(parser.pbxproj, proj.writeSync(), 'utf-8');
                    // Move the xcodeproj and other name-based dirs over.
                    shell.mv(path.join(parser.cordovaproj, parser.originalName + '-Info.plist'), path.join(parser.cordovaproj, name + '-Info.plist'));
                    shell.mv(path.join(parser.cordovaproj, parser.originalName + '-Prefix.pch'), path.join(parser.cordovaproj, name + '-Prefix.pch'));
                    shell.mv(parser.xcodeproj, path.join(parser.path, name + '.xcodeproj'));
                    shell.mv(parser.cordovaproj, path.join(parser.path, name));
                    // Update self object with new paths
                    var old_name = parser.originalName;
                    parser = new module.exports(parser.path);
                    // Hack this shi*t
                    var pbx_contents = fs.readFileSync(parser.pbxproj, 'utf-8');
                    pbx_contents = pbx_contents.split(old_name).join(name);
                    fs.writeFileSync(parser.pbxproj, pbx_contents, 'utf-8');
                    events.emit('verbose', 'Wrote out iOS Product Name and updated XCode project file names from "'+old_name+'" to "' + name + '".');
                    d.resolve();
                }
            });
            return d.promise;
        } else {
            events.emit('verbose', 'iOS Product Name has not changed (still "' + this.originalName + '")');
            return Q();
        }
    },

    // Returns the platform-specific www directory.
    www_dir:function() {
        return path.join(this.path, 'xface3', 'helloxface');
    },

    staging_dir: function() {
        return path.join(this.path, '.staging', 'www');
    },

    config_xml:function(){
        return this.config_path;
    },

    update_www:function() {
        var projectRoot = util.isxFace(this.path);
        var www = util.projectWww(projectRoot);
        var parentWww = path.resolve(path.join(this.www_dir(), '..'));

        // remove the stock www folder
        shell.rm('-rf', parentWww);
        shell.mkdir('-p', parentWww);

        // copy over project www assets
        shell.cp('-rf', www + '/*', parentWww);

        // write out proper xface.js
        var custom_path = config.has_custom_path(projectRoot, 'ios');
        var lib_path = util.getDefaultPlatformLibPath(projectRoot, 'ios');
        if (custom_path) lib_path = custom_path;
        shell.cp('-f', path.join(lib_path, 'xFaceLib', 'xFaceLib', 'xface.js'), path.join(this.www_dir(), 'xface.js'));
    },

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

    // update the overrides folder into the www folder
    update_staging:function() {
        var projectRoot = util.isxFace(this.path);
        if (fs.existsSync(this.staging_dir())) {
            var staging = path.join(this.staging_dir(), '*');
            shell.cp('-rf', staging, this.www_dir());
        }
    },

    // Returns a promise.
    update_project:function(cfg) {
        var self = this;
        return this.update_from_config(cfg)
        .then(function() {
            self.update_www();
            self.update_overrides();
            self.update_staging();
            util.deleteSvnFolders(self.www_dir());
        });
    }
};
<|endoftext|>


<commit_before>/**
 * @author bh-lay
 * @github https://github.com/bh-lay/tie.js
 * @modified 2015-10-23 18:31
 *
 * 处理既要相对于某个模块固定，又要在其可视时悬浮的页面元素
 * util.tie({
		dom: ,			//需要浮动的元素
		scopeDom: ,		//页面显示时的参照元素
		fixed_top: 20	//悬浮时，距顶部的距离
	});
 *
 */

(function(global,doc,factory_fn){
	global.util = global.util || {};
	global.util.tie = factory_fn(global,doc);

	global.define && define(function(){
		return global.util.tie;
	});
})(window,document,function(window,document){
	var private_body = document.body || document.getElementsByTagName("body")[0],
		docDom = document.compatMode == "BackCompat" ? private_body : document.documentElement;

	function doc_scrollTop(){
	    return docDom.scrollTop || private_body.scrollTop;
	}
	/**
	 * 检测是否为数字
	 * 兼容字符类数字 '23'
	 **/
	function isNum(ipt){
		return (ipt !== '') && (ipt == +ipt) ? true : false;
	}

	/**
	 * 遍历数组或对象
	 *
	**/
	function each(arr,fn){
		//检测输入的值
		if(typeof(arr) != 'object' || typeof(fn) != 'function'){
			return;
		}
		var Length = arr.length;
		if( isNum(Length) ){
			for(var i=0;i<Length;i++){
				if(fn.call(this,i,arr[i]) === false){
					break
				}
			}
		}else{
			for(var i in arr){
				if (!arr.hasOwnProperty(i)){
					continue;
				}
				if(fn.call(this,i,arr[i]) === false){
					break
				}
			}
		}
	}
	/**
	* dom设置样式
	*/
	function setStyle(elem,prop,value){
		prop = prop.toString();
		if (prop == "opacity") {
			elem.style.filter = 'alpha(opacity=' + (value * 100)+ ')';
			value = value;
		} else if ( isNum(value) && prop != 'zIndex'){
			value = value + "px";
		}
		elem.style[prop] = value;
	}
	//设置css
	function setCss(doms,cssObj){
		doms = [].concat(doms);
		each(doms,function(i,dom){
			each(cssObj,function(key,value){
				setStyle(dom,key,value);
			});
		});
	}
  	/**
	 * 事件绑定
	 * elem:节点
	 * type:事件类型
	 * handler:回调
	 **/
	var bindHandler = window.addEventListener ? function(elem, type, handler) {
			elem.addEventListener(type, handler, false);
		} : function(elem, type, handler) {
			elem.attachEvent("on" + type, handler);
		};
	/**
	* 事件解除
	* elem:节点
	* type:事件类型
	* handler:回调
	*/
	var removeHandler = window.removeEventListener ? function(elem, type, handler) {
			elem.removeEventListener(type, handler, false);
		} : function(elem, type, handler) {
			elem.detachEvent("on" + type, handler);
		};
	function getClient(elem){
		var box = {
			top : 0,
			left : 0,
			width: 0,
			height: 0,
			screen_top : 0,
			screen_left : 0
		},
		size = elem.getBoundingClientRect();

		box.width = size.width || (size.right - size.left);
		box.height = size.height || (size.bottom - size.top);
		box.screen_top = size.top;
		box.screen_left = size.left;

		box.top = size.top + (document.documentElement.scrollTop == 0 ? document.body.scrollTop : document.documentElement.scrollTop);
		box.left = size.left + document.body.scrollLeft;

		return box;
	}

	//获取样式
	function getStyle(elem, prop) {
		var value;
		if (elem.style[prop]){
			value = elem.style[prop];
		} else if(document.defaultView) {
			var style = document.defaultView.getComputedStyle(elem, null);
			value = prop in style ? style[prop] : style.getPropertyValue(prop);
		} else if (elem.currentStyle) {
			value = elem.currentStyle[prop];
		}

		if (/\px$/.test(value)){
			value = parseInt(value);
		}else if (isNum(value) ){
			value = Number(value);
		} else if (value == 'auto'){
			if(prop == 'height'){
				value = elem.clientHeight;
			}else if(prop == 'width'){
				value = elem.clientWidth;
			}
		}
		return value;
	}

	function resetPosition(){
		var me = this,
			scopeClient = getClient(me.scopeDom),
			scrollTop = doc_scrollTop(),
			state_before = me.state,
			top,position;

		me.minScrollTop = getClient(me.ghostDom).top - me.fix_top;
		me.maxScrollTop = scopeClient.top + scopeClient.height - getClient(me.dom).height - me.fix_top;

		if(scrollTop <= me.minScrollTop){
			me.state = 'min';
			top = 0;
			position =  'relative';
		}else if(scrollTop >= me.maxScrollTop){
			me.state = 'max';
			top = scopeClient.top + scopeClient.height - getClient(me.ghostDom).top - getClient(me.dom).height;
			position = 'relative';
		}else{
			me.state = 'mid';
			top = me.fix_top;
			position = 'fixed';
		}

		setCss(me.dom, {
			top: top,
			position: position
		});

		if(state_before != me.state){
			me.onPositionChange && me.onPositionChange.call(me,me.state);
			me.updateGhostDom();
		}
	}
	function Tie(param){
		if( !(this instanceof Tie)){
			return new Tie(param);
		}
		var me = this,
			scroll_delay;
		param = param || {};
		//悬浮时，距顶部的距离
		me.fix_top = param.fixed_top || 0;
		me.minScrollTop = null;
		me.maxScrollTop = null;

		//悬浮dom
		me.dom = param.dom;
		me.scrollDom = param.scrollDom || window;
		//从属dom
		me.scopeDom = param.scopeDom;
		//占位dom
		me.ghostDom = document.createElement('div');

	    //将占位dom放置在悬浮dom前
    	me.dom.parentNode.insertBefore(me.ghostDom,me.dom);
	    //再将悬浮dom移入占位dom内
	    me.ghostDom.appendChild(me.dom);

		//当定位方式发生变化时
		me.onPositionChange = param.onPositionChange || null;

		me.state = 'min';
		me._scroll_listener = resetPosition.bind(this);

		me.refresh();

		if(getStyle(me.scopeDom,'position') == 'static'){
			me.scopeDom.style.position = 'relative';
		}
		bindHandler(me.scrollDom,'scroll',me._scroll_listener);
	}
	Tie.prototype = {
		refresh: resetPosition,
		updateGhostDom: function(){
			this.ghostDom.style.height = getClient(this.dom).height + 'px';
		},
		destroy: function(){
			removeHandler(this.scrollDom,'scroll',this._scroll_listener);
			setCss(this.dom,{
				position: 'relative',
				top: getClient(this.dom).top - getClient(this.ghostDom).top
			});
		}
	};
	return Tie;
});<commit_msg>增加组件事件监听<commit_after>/**
 * @author bh-lay
 * @github https://github.com/bh-lay/tie.js
 * @modified 2015-12-07 18:21
 *
 * 处理既要相对于某个模块固定，又要在其可视时悬浮的页面元素
 * util.tie({
		dom: ,			//需要浮动的元素
		scopeDom: ,		//页面显示时的参照元素
		fixed_top: 20	//悬浮时，距顶部的距离
	});
 *
 */

(function(global,doc,factory_fn){
	global.util = global.util || {};
	global.util.tie = factory_fn(global,doc);

	global.define && define(function(){
		return global.util.tie;
	});
})(window,document,function(window,document){
	var private_body = document.body || document.getElementsByTagName("body")[0],
		docDom = document.compatMode == "BackCompat" ? private_body : document.documentElement;

	function doc_scrollTop(){
	    return docDom.scrollTop || private_body.scrollTop;
	}
	/**
	 * 检测是否为数字
	 * 兼容字符类数字 '23'
	 **/
	function isNum(ipt){
		return (ipt !== '') && (ipt == +ipt) ? true : false;
	}

	/**
	 * 遍历数组或对象
	 *
	**/
	function each(arr,fn){
		//检测输入的值
		if(typeof(arr) != 'object' || typeof(fn) != 'function'){
			return;
		}
		var Length = arr.length;
		if( isNum(Length) ){
			for(var i=0;i<Length;i++){
				if(fn.call(this,i,arr[i]) === false){
					break
				}
			}
		}else{
			for(var i in arr){
				if (!arr.hasOwnProperty(i)){
					continue;
				}
				if(fn.call(this,i,arr[i]) === false){
					break
				}
			}
		}
	}
	/**
	* dom设置样式
	*/
	function setStyle(elem,prop,value){
		prop = prop.toString();
		if (prop == "opacity") {
			elem.style.filter = 'alpha(opacity=' + (value * 100)+ ')';
			value = value;
		} else if ( isNum(value) && prop != 'zIndex'){
			value = value + "px";
		}
		elem.style[prop] = value;
	}
	//设置css
	function setCss(doms,cssObj){
		doms = [].concat(doms);
		each(doms,function(i,dom){
			each(cssObj,function(key,value){
				setStyle(dom,key,value);
			});
		});
	}
  	/**
	 * 事件绑定
	 * elem:节点
	 * type:事件类型
	 * handler:回调
	 **/
	var bindHandler = window.addEventListener ? function(elem, type, handler) {
			elem.addEventListener(type, handler, false);
		} : function(elem, type, handler) {
			elem.attachEvent("on" + type, handler);
		};
	/**
	* 事件解除
	* elem:节点
	* type:事件类型
	* handler:回调
	*/
	var removeHandler = window.removeEventListener ? function(elem, type, handler) {
			elem.removeEventListener(type, handler, false);
		} : function(elem, type, handler) {
			elem.detachEvent("on" + type, handler);
		};
	function getClient(elem){
		var box = {
			top : 0,
			left : 0,
			width: 0,
			height: 0,
			screen_top : 0,
			screen_left : 0
		},
		size = elem.getBoundingClientRect();

		box.width = size.width || (size.right - size.left);
		box.height = size.height || (size.bottom - size.top);
		box.screen_top = size.top;
		box.screen_left = size.left;

		box.top = size.top + (document.documentElement.scrollTop == 0 ? document.body.scrollTop : document.documentElement.scrollTop);
		box.left = size.left + document.body.scrollLeft;

		return box;
	}

	//获取样式
	function getStyle(elem, prop) {
		var value;
		if (elem.style[prop]){
			value = elem.style[prop];
		} else if(document.defaultView) {
			var style = document.defaultView.getComputedStyle(elem, null);
			value = prop in style ? style[prop] : style.getPropertyValue(prop);
		} else if (elem.currentStyle) {
			value = elem.currentStyle[prop];
		}

		if (/\px$/.test(value)){
			value = parseInt(value);
		}else if (isNum(value) ){
			value = Number(value);
		} else if (value == 'auto'){
			if(prop == 'height'){
				value = elem.clientHeight;
			}else if(prop == 'width'){
				value = elem.clientWidth;
			}
		}
		return value;
	}

	function resetPosition(){
		var me = this,
			scopeClient = getClient(me.scopeDom),
			scrollTop = doc_scrollTop(),
			state_before = me.state,
			top,position;

		me.minScrollTop = getClient(me.ghostDom).top - me.fix_top;
		me.maxScrollTop = scopeClient.top + scopeClient.height - getClient(me.dom).height - me.fix_top;

		if(scrollTop <= me.minScrollTop){
			me.state = 'min';
			top = 0;
			position =  'relative';
		}else if(scrollTop >= me.maxScrollTop){
			me.state = 'max';
			top = scopeClient.top + scopeClient.height - getClient(me.ghostDom).top - getClient(me.dom).height;
			position = 'relative';
		}else{
			me.state = 'mid';
			top = me.fix_top;
			position = 'fixed';
		}

		setCss(me.dom, {
			top: top,
			position: position
		});

		if(state_before != me.state){
			me.onPositionChange && me.onPositionChange.call(me,me.state);
			me.updateGhostDom();
		}
	}
	function Tie(param){
		if( !(this instanceof Tie)){
			return new Tie(param);
		}
		var me = this,
			scroll_delay;
		param = param || {};
		//悬浮时，距顶部的距离
		me.fix_top = param.fixed_top || 0;
		me.minScrollTop = null;
		me.maxScrollTop = null;

		//悬浮dom
		me.dom = param.dom;
		me.scrollDom = param.scrollDom || window;
		//从属dom
		me.scopeDom = param.scopeDom;
		//占位dom
		me.ghostDom = document.createElement('div');

	    //将占位dom放置在悬浮dom前
    	me.dom.parentNode.insertBefore(me.ghostDom,me.dom);
	    //再将悬浮dom移入占位dom内
	    me.ghostDom.appendChild(me.dom);

		//当定位方式发生变化时
		me.onPositionChange = param.onPositionChange || null;

		me.state = 'min';
		me._scroll_resize_listener = resetPosition.bind(this);

		me.refresh();

		if(getStyle(me.scopeDom,'position') == 'static'){
			me.scopeDom.style.position = 'relative';
		}
		bindHandler(me.scrollDom,'scroll',me._scroll_resize_listener);
		bindHandler(window,'resize',me._scroll_resize_listener);
	}
	Tie.prototype = {
		refresh: resetPosition,
		updateGhostDom: function(){
			this.ghostDom.style.height = getClient(this.dom).height + 'px';
		},
		destroy: function(){
			removeHandler(this.scrollDom,'scroll',this._scroll_resize_listener);
			removebindHandler(window,'resize',me._scroll_resize_listener);
			setCss(this.dom,{
				position: 'relative',
				top: getClient(this.dom).top - getClient(this.ghostDom).top
			});
		}
	};
	return Tie;
});
<|endoftext|>


<commit_before>$(document).ready(function() {
	$("#a_1874").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1874.png");
	});
	$("#a_1880").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1880.png");
	});
	$("#a_1885").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1885.png");
	});
	$("#a_1890").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1890.png");
	});
	$("#a_1895").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1895.png");
	});
	$("#a_1900").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1900.png");
	});
	$("#a_1905").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1905.png");
	});
	$("#a_1910").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1910.png");
	});
	$("#a_1915").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1915.png");
	});
	$("#a_1920").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1920.png");
	});
	$("#a_1930").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1930.png");
	});
	$("#a_1940").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1940.png");
	});
	$("#a_1950").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1950.png");
	});
	$("#a_1960").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1960.png");
	});
	$("#a_1970").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1970.png");
	});
	$("#a_1980").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1980.png");
	});
	$("#a_1988").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1988.png");
	});
        var map_array = ["GT_1949-min.png", "GT_1954-min.png", "GT_1959-min.png", "GT_1964-min.png", "GT_1969-min.png", "GT_1974-min.png", "GT_1978-min.png", "GT_1982-min.png", "GT_1987-min.png", "GT_1992-min.png", "GT_1997-min.png", "GT_2002-min.png", "GT_2007-min.png", "GT_2012-min.png"];
        $("#play1").on("click", function() {
            $("#play1").prop("disabled", true);
            var c = 0;
            interval = setInterval(function() {
                if (c>12) {
                    clearInterval(interval);
                    $("#play1").prop("disabled", false);
                }
                switch_func(c);
                c++;
            }, 2000);

        function switch_func(c) {
            $("#map").attr("src", "/images/maps/"+map_array[c]);
        }
    });
});
<commit_msg>got ghost towns button working<commit_after>$(document).ready(function() {
	$("#a_1874").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1874.png");
	});
	$("#a_1880").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1880.png");
	});
	$("#a_1885").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1885.png");
	});
	$("#a_1890").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1890.png");
	});
	$("#a_1895").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1895.png");
	});
	$("#a_1900").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1900.png");
	});
	$("#a_1905").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1905.png");
	});
	$("#a_1910").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1910.png");
	});
	$("#a_1915").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1915.png");
	});
	$("#a_1920").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1920.png");
	});
	$("#a_1930").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1930.png");
	});
	$("#a_1940").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1940.png");
	});
	$("#a_1950").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1950.png");
	});
	$("#a_1960").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1960.png");
	});
	$("#a_1970").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1970.png");
	});
	$("#a_1980").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1980.png");
	});
	$("#a_1988").on("click", function() {
		$("#map").attr("src", "/images/maps/GT_C1988.png");
	});
        var map_array = ["GT_C1874.png", "GT_C1880.png", "GT_C1885.png", "GT_C1890.png", "GT_C1895.png", "GT_C1900.png", "GT_C1905.png", "GT_C1910.png", "GT_C1915.png", "GT_C1920.png", "GT_C1930.png", "GT_C1940.png", "GT_C1950.png", "GT_C1960.png", "GT_C1970.png", "GT_C1980.png", "GT_C1988.png"];
        $("#play1").on("click", function() {
            $("#play1").prop("disabled", true);
            var c = 0;
            interval = setInterval(function() {
                if (c>15) {
                    clearInterval(interval);
                    $("#play1").prop("disabled", false);
                }
                switch_func(c);
                c++;
            }, 2000);

        function switch_func(c) {
            $("#map").attr("src", "/images/maps/"+map_array[c]);
        }
    });
});
<|endoftext|>


<commit_before>import fetcher         from "../fetcher";
import clone           from "../utils/cloneFunction";

export default function get(id)  {

    // let url = (id) ? `${urlBase}${sourceName}/${id}` : `${urlBase}${sourceName}`;
    let url = get.url;
    let cache = get.cache;

    if (typeof id === "undefined") {

        // console.log("log: Resource->get:", url);

        return new Promise((resolve, response) => {

            if (typeof cache !== "undefined" && cache !== null) {
                let cacheItem = cache.type.get(url);
                if (cacheItem) {
                    let now = (new Date()).getTime();
                    // use cache
                    if (cacheItem.expires > now) {
                        resolve(cacheItem.value);
                        return;
                    // remove expired cacheItem
                    } else {
                        cache.type.remove(url);
                    }
                }
            }

            let fetchCallback = (value) => {

                if (typeof cache === "undefined" || cache === null)
                    return;

                let {
                        expires: cacheExpires,
                        type: cacheType
                    } = cache;

                cacheExpires = parseInt(cacheExpires)*1000;
                let expireDate = (new Date()).getTime()+cacheExpires;
                cacheType.add(url, value, expireDate);

            };

            get.fetcher('GET', url, null, fetchCallback)
                .then(resolve)
                .catch(response);

        });

    } else {

        // Create clone route
        let clone = get.clone();//new Function('return ' + get.toString())();

        clone.url = `${url}/${id}`;

        // copy sub routes too
        for (i in get) {
           if (typeof get[i] !== "function") continue;
           clone[i] = get[i];
           clone[i].url =  `${clone.url}/${i}`;
        }

        return clone;
    }

};

// scoped
get.fetcher = fetcher;
get.cache = null;
get.clone = clone.bind(get);
<commit_msg>chore(get): remove comment<commit_after>import fetcher         from "../fetcher";
import clone           from "../utils/cloneFunction";

export default function get(id)  {

    // let url = (id) ? `${urlBase}${sourceName}/${id}` : `${urlBase}${sourceName}`;
    let url = get.url;
    let cache = get.cache;

    if (typeof id === "undefined") {

        // console.log("log: Resource->get:", url);

        return new Promise((resolve, response) => {

            if (typeof cache !== "undefined" && cache !== null) {
                let cacheItem = cache.type.get(url);
                if (cacheItem) {
                    let now = (new Date()).getTime();
                    // use cache
                    if (cacheItem.expires > now) {
                        resolve(cacheItem.value);
                        return;
                    // remove expired cacheItem
                    } else {
                        cache.type.remove(url);
                    }
                }
            }

            let fetchCallback = (value) => {

                if (typeof cache === "undefined" || cache === null)
                    return;

                let {
                        expires: cacheExpires,
                        type: cacheType
                    } = cache;

                cacheExpires = parseInt(cacheExpires)*1000;
                let expireDate = (new Date()).getTime()+cacheExpires;
                cacheType.add(url, value, expireDate);

            };

            get.fetcher('GET', url, null, fetchCallback)
                .then(resolve)
                .catch(response);

        });

    } else {

        // Create clone route
        let clone = get.clone();

        clone.url = `${url}/${id}`;

        // copy sub routes too
        for (i in get) {
           if (typeof get[i] !== "function") continue;
           clone[i] = get[i];
           clone[i].url =  `${clone.url}/${i}`;
        }

        return clone;
    }

};

// scoped
get.fetcher = fetcher;
get.cache = null;
get.clone = clone.bind(get);
<|endoftext|>