<commit_before>/*
Copyright 2017 The BioBricks Foundation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

var AJV = require('ajv')
var attachmentPath = require('./util/attachment-path')
var concat = require('simple-concat')
var crypto = require('crypto')
var encoding = require('./encoding')
var flushWriteStream = require('flush-write-stream')
var fs = require('fs')
var https = require('https')
var latest = require('./latest')
var mkdirp = require('mkdirp')
var once = require('once')
var parse = require('json-parse-errback')
var path = require('path')
var pump = require('pump')
var recordDirectoryPath = require('./util/record-directory-path')
var recordPath = require('./util/record-path')
var runParallel = require('run-parallel')
var runSeries = require('run-series')
var sodium = require('sodium-native')
var stringify = require('json-stable-stringify')
var through2 = require('through2')
var timestampPath = require('./util/timestamp-path')
var uuid = require('uuid/v4')

var publicationSchema = latest(require('pdc-publication-schema'))
var timestampSchema = latest(require('pdc-timestamp-schema'))

var validatePublication = new AJV({allErrors: true})
  .compile(publicationSchema)

// TODO: Delete attachment files in /tmp for invalid publications.

// Create a writable stream that accepts one or more attachment chunks,
// followed by a publication chunk, and writes files and a signed
// timestamp to the data directory.
//
// Attachment chunks look like:
//
//     {
//       type: 'attachment',
//       stream: Readable,
//       filename: String,
//       encoding: String,
//       mimetype: String
//     }
//
// Publication fields contain JSON data.
module.exports = function (configuration, log, callback) {
  var directory = configuration.directory
  var attachments = []
  var validPublication = false
  return flushWriteStream.obj(
    function (object, _, done) {
      if (object.type === 'attachment') {
        writeAttachment(object, done)
      } else {
        writePublication(object, function (error, digest) {
          if (error) return done(error)
          validPublication = digest
          done()
        })
      }
    },
    function (done) {
      if (validPublication) {
        callback(validPublication)
      } else {
        runParallel(
          attachments.map(function (attachment) {
            return function unlinkTemporaryFile (done) {
              fs.unlink(attachment.temporaryFile, function (error) {
                log.error(error)
                done()
              })
            }
          }),
          function () {
            done()
          }
        )
      }
    }
  )

  function writeAttachment (object, callback) {
    // Save to ./tmp/{UUID}.
    var id = uuid()
    var temporaryFile = path.join(directory, 'tmp', id)
    var attachment = {
      stream: object.stream,
      temporaryFile: temporaryFile,
      type: object.mimetype + '; charset=' + object.encoding
    }
    log.info('attachment', {
      uuid: id,
      filename: object.filename,
      encoding: object.encoding,
      mimetype: object.mimetype
    })
    attachments.push(attachment)
    var hash = crypto.createHash('sha256')
    var size = 0
    pump(
      object.stream,
      // Compute SHA256 as we write to disk.
      through2(function (chunk, chunkEncoding, done) {
        size += chunk.length
        hash.update(chunk, chunkEncoding)
        this.push(chunk, chunkEncoding)
        done()
      }),
      fs.createWriteStream(temporaryFile),
      function (error) {
        /* istanbul ignore next */
        if (error) {
          callback(error)
        } else {
          if (size === 0) {
            var index = attachments.indexOf(attachment)
            attachments.splice(index, 1)
          } else {
            attachment.digest = encoding.encode(hash.digest())
          }
          callback()
        }
      }
    )
  }

  function writePublication (publication, callback) {
    var secretKey = configuration.keypair.secret
    var publicKey = configuration.keypair.public
    var time = new Date().toISOString()
    publication.attachments = attachments
      .map(function (attachment) {
        return attachment.digest
      })
      .sort()
    log.info('publication', publication)
    publication.version = '1.0.0'
    validatePublication(publication)
    var validationErrors = validatePublication.errors
    if (validationErrors) {
      log.info('validationErrors', validationErrors)
      var validationError = new Error('Invalid input')
      validationError.validationErrors = validationErrors
      callback(validationError)
    } else {
      var record = Buffer.from(stringify(publication), 'utf8')
      var digest = Buffer.alloc(sodium.crypto_hash_sha256_BYTES)
      sodium.crypto_hash_sha256(digest, record)
      digest = encoding.encode(digest)
      var uri = (
        'https://' + configuration.hostname +
        '/publications/' + digest
      )
      var timestamp = {
        digest: digest,
        uri: uri,
        time: time
      }
      var signature = Buffer.alloc(sodium.crypto_sign_BYTES)
      sodium.crypto_sign_detached(
        signature,
        Buffer.from(stringify(timestamp)),
        secretKey
      )
      runSeries([
        function writeJSONFile (done) {
          fs.writeFile(recordPath(directory, digest), record, done)
        },
        function createDirectory (done) {
          mkdirp(recordDirectoryPath(directory, digest), done)
        },
        function writeTimestampFile (done) {
          fs.writeFile(
            timestampPath(directory, digest, publicKey),
            stringify({
              timestamp: timestamp,
              signature: encoding.encode(signature),
              version: timestampSchema.properties.version.const
            }),
            done
          )
        },
        function writeAttachments (done) {
          if (attachments.length > 0) {
            runParallel(
              attachments.reduce(
                function (tasks, attachment) {
                  var file = attachmentPath(
                    directory, digest, attachment.digest
                  )
                  return tasks.concat([
                    function writeTypeFile (done) {
                      fs.writeFile(
                        file + '.type',
                        attachment.type,
                        'utf8',
                        done
                      )
                    },
                    function moveFile (done) {
                      fs.rename(
                        attachment.temporaryFile, file,
                        done
                      )
                    }
                  ])
                },
                []
              ),
              done
            )
          } else {
            done()
          }
        },
        function appendToAccessions (done) {
          fs.appendFile(
            path.join(directory, 'accessions'),
            time + ',' + digest + '\n',
            done
          )
        },
        function stampWithStampery (done) {
          if (configuration.stampery) {
            stamp(configuration, log, digest, done)
          } else {
            done()
          }
        }
      ], function (error) {
        /* istanbul ignore if */
        if (error) {
          error.statusCode = 500
          callback(error)
        } else {
          callback(null, digest)
        }
      })
    }
  }
}

function stamp (configuration, log, digest, callback) {
  callback = once(callback)
  var auth = (
    configuration.stampery.user + ':' +
    configuration.stampery.password
  )
  https.request({
    host: 'api-prod.stampery.com',
    path: '/stamps/' + digest,
    auth: auth
  })
    .once('error', function (error) {
      log.error(error)
      callback()
    })
    .once('response', function (response) {
      concat(response, function (error, buffer) {
        if (error) {
          log.error(error)
          callback()
        } else {
          parse(buffer, function (error, data) {
            if (error) {
              log.error(error)
              callback()
            } else if (data.error) {
              log.error(data)
              callback()
            } else if (!Array.isArray(data.results)) {
              log.error('no stampery results')
              callback()
            } else {
              if (data.results.length !== 0) {
                log.info('already stamped')
                callback()
              } else {
                https.request({
                  method: 'POST',
                  host: 'api-prod.stampery.com',
                  path: '/stamps',
                  auth: auth,
                  headers: {
                    'Content-Type': 'application/json'
                  }
                })
                  .once('error', function (error) {
                    log.error(error)
                    callback()
                  })
                  .once('response', function (response) {
                    concat(response, function (error, buffer) {
                      if (error) {
                        log.error(error)
                        callback()
                      } else {
                        parse(buffer, function (error, data) {
                          if (error) {
                            log.error(error)
                          } else if (data.error) {
                            log.error(data.error)
                          } else if (!data.result) {
                            log.error('no stampery result')
                          } else {
                            log.info(data.result, 'stamp')
                          }
                          callback()
                        })
                      }
                    })
                  })
                  .end(JSON.stringify({hash: digest}))
              }
            }
          })
        }
      })
    })
    .end()
}
<commit_msg>Add TODO<commit_after>/*
Copyright 2017 The BioBricks Foundation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

var AJV = require('ajv')
var attachmentPath = require('./util/attachment-path')
var concat = require('simple-concat')
var crypto = require('crypto')
var encoding = require('./encoding')
var flushWriteStream = require('flush-write-stream')
var fs = require('fs')
var https = require('https')
var latest = require('./latest')
var mkdirp = require('mkdirp')
var once = require('once')
var parse = require('json-parse-errback')
var path = require('path')
var pump = require('pump')
var recordDirectoryPath = require('./util/record-directory-path')
var recordPath = require('./util/record-path')
var runParallel = require('run-parallel')
var runSeries = require('run-series')
var sodium = require('sodium-native')
var stringify = require('json-stable-stringify')
var through2 = require('through2')
var timestampPath = require('./util/timestamp-path')
var uuid = require('uuid/v4')

var publicationSchema = latest(require('pdc-publication-schema'))
var timestampSchema = latest(require('pdc-timestamp-schema'))

var validatePublication = new AJV({allErrors: true})
  .compile(publicationSchema)

// TODO: Delete attachment files in /tmp for invalid publications.
// TODO: republish publications on any valid schema

// Create a writable stream that accepts one or more attachment chunks,
// followed by a publication chunk, and writes files and a signed
// timestamp to the data directory.
//
// Attachment chunks look like:
//
//     {
//       type: 'attachment',
//       stream: Readable,
//       filename: String,
//       encoding: String,
//       mimetype: String
//     }
//
// Publication fields contain JSON data.
module.exports = function (configuration, log, callback) {
  var directory = configuration.directory
  var attachments = []
  var validPublication = false
  return flushWriteStream.obj(
    function (object, _, done) {
      if (object.type === 'attachment') {
        writeAttachment(object, done)
      } else {
        writePublication(object, function (error, digest) {
          if (error) return done(error)
          validPublication = digest
          done()
        })
      }
    },
    function (done) {
      if (validPublication) {
        callback(validPublication)
      } else {
        runParallel(
          attachments.map(function (attachment) {
            return function unlinkTemporaryFile (done) {
              fs.unlink(attachment.temporaryFile, function (error) {
                log.error(error)
                done()
              })
            }
          }),
          function () {
            done()
          }
        )
      }
    }
  )

  function writeAttachment (object, callback) {
    // Save to ./tmp/{UUID}.
    var id = uuid()
    var temporaryFile = path.join(directory, 'tmp', id)
    var attachment = {
      stream: object.stream,
      temporaryFile: temporaryFile,
      type: object.mimetype + '; charset=' + object.encoding
    }
    log.info('attachment', {
      uuid: id,
      filename: object.filename,
      encoding: object.encoding,
      mimetype: object.mimetype
    })
    attachments.push(attachment)
    var hash = crypto.createHash('sha256')
    var size = 0
    pump(
      object.stream,
      // Compute SHA256 as we write to disk.
      through2(function (chunk, chunkEncoding, done) {
        size += chunk.length
        hash.update(chunk, chunkEncoding)
        this.push(chunk, chunkEncoding)
        done()
      }),
      fs.createWriteStream(temporaryFile),
      function (error) {
        /* istanbul ignore next */
        if (error) {
          callback(error)
        } else {
          if (size === 0) {
            var index = attachments.indexOf(attachment)
            attachments.splice(index, 1)
          } else {
            attachment.digest = encoding.encode(hash.digest())
          }
          callback()
        }
      }
    )
  }

  function writePublication (publication, callback) {
    var secretKey = configuration.keypair.secret
    var publicKey = configuration.keypair.public
    var time = new Date().toISOString()
    publication.attachments = attachments
      .map(function (attachment) {
        return attachment.digest
      })
      .sort()
    log.info('publication', publication)
    publication.version = '1.0.0'
    validatePublication(publication)
    var validationErrors = validatePublication.errors
    if (validationErrors) {
      log.info('validationErrors', validationErrors)
      var validationError = new Error('Invalid input')
      validationError.validationErrors = validationErrors
      callback(validationError)
    } else {
      var record = Buffer.from(stringify(publication), 'utf8')
      var digest = Buffer.alloc(sodium.crypto_hash_sha256_BYTES)
      sodium.crypto_hash_sha256(digest, record)
      digest = encoding.encode(digest)
      var uri = (
        'https://' + configuration.hostname +
        '/publications/' + digest
      )
      var timestamp = {
        digest: digest,
        uri: uri,
        time: time
      }
      var signature = Buffer.alloc(sodium.crypto_sign_BYTES)
      sodium.crypto_sign_detached(
        signature,
        Buffer.from(stringify(timestamp)),
        secretKey
      )
      runSeries([
        function writeJSONFile (done) {
          fs.writeFile(recordPath(directory, digest), record, done)
        },
        function createDirectory (done) {
          mkdirp(recordDirectoryPath(directory, digest), done)
        },
        function writeTimestampFile (done) {
          fs.writeFile(
            timestampPath(directory, digest, publicKey),
            stringify({
              timestamp: timestamp,
              signature: encoding.encode(signature),
              version: timestampSchema.properties.version.const
            }),
            done
          )
        },
        function writeAttachments (done) {
          if (attachments.length > 0) {
            runParallel(
              attachments.reduce(
                function (tasks, attachment) {
                  var file = attachmentPath(
                    directory, digest, attachment.digest
                  )
                  return tasks.concat([
                    function writeTypeFile (done) {
                      fs.writeFile(
                        file + '.type',
                        attachment.type,
                        'utf8',
                        done
                      )
                    },
                    function moveFile (done) {
                      fs.rename(
                        attachment.temporaryFile, file,
                        done
                      )
                    }
                  ])
                },
                []
              ),
              done
            )
          } else {
            done()
          }
        },
        function appendToAccessions (done) {
          fs.appendFile(
            path.join(directory, 'accessions'),
            time + ',' + digest + '\n',
            done
          )
        },
        function stampWithStampery (done) {
          if (configuration.stampery) {
            stamp(configuration, log, digest, done)
          } else {
            done()
          }
        }
      ], function (error) {
        /* istanbul ignore if */
        if (error) {
          error.statusCode = 500
          callback(error)
        } else {
          callback(null, digest)
        }
      })
    }
  }
}

function stamp (configuration, log, digest, callback) {
  callback = once(callback)
  var auth = (
    configuration.stampery.user + ':' +
    configuration.stampery.password
  )
  https.request({
    host: 'api-prod.stampery.com',
    path: '/stamps/' + digest,
    auth: auth
  })
    .once('error', function (error) {
      log.error(error)
      callback()
    })
    .once('response', function (response) {
      concat(response, function (error, buffer) {
        if (error) {
          log.error(error)
          callback()
        } else {
          parse(buffer, function (error, data) {
            if (error) {
              log.error(error)
              callback()
            } else if (data.error) {
              log.error(data)
              callback()
            } else if (!Array.isArray(data.results)) {
              log.error('no stampery results')
              callback()
            } else {
              if (data.results.length !== 0) {
                log.info('already stamped')
                callback()
              } else {
                https.request({
                  method: 'POST',
                  host: 'api-prod.stampery.com',
                  path: '/stamps',
                  auth: auth,
                  headers: {
                    'Content-Type': 'application/json'
                  }
                })
                  .once('error', function (error) {
                    log.error(error)
                    callback()
                  })
                  .once('response', function (response) {
                    concat(response, function (error, buffer) {
                      if (error) {
                        log.error(error)
                        callback()
                      } else {
                        parse(buffer, function (error, data) {
                          if (error) {
                            log.error(error)
                          } else if (data.error) {
                            log.error(data.error)
                          } else if (!data.result) {
                            log.error('no stampery result')
                          } else {
                            log.info(data.result, 'stamp')
                          }
                          callback()
                        })
                      }
                    })
                  })
                  .end(JSON.stringify({hash: digest}))
              }
            }
          })
        }
      })
    })
    .end()
}
<|endoftext|>


<commit_before>'use strict';
export function getConfig() {
    return userConfig;
}

let userConfig = {
    lockView: true,
    debugLevel: 0,
    filters: [],
    modules: {
        folders: ['modules/types']
    },
    header: false
};

<commit_msg>remove lockview from visualizer config<commit_after>'use strict';
export function getConfig() {
    return userConfig;
}

let userConfig = {
    debugLevel: 0,
    filters: [],
    modules: {
        folders: ['modules/types']
    },
    header: false
};

<|endoftext|>


<commit_before>import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from '../helpers/start-app';
import { lookupComponent } from '../helpers/lookup';

const {
  EnumerableUtils,
  run
} = Ember;

const {
  map,
  filter
} = EnumerableUtils;

let application;
let componentInstance;

module('Acceptance | ember-crumbly integration test', {
  beforeEach() {
    application = startApp();
    componentInstance = lookupComponent(application, 'bread-crumbs');
  },

  afterEach() {
    componentInstance = null;
    run(application, 'destroy');
  }
});

test('routeHierarchy returns the correct number of routes', function(assert) {
  assert.expect(2);
  visit('/foo/bar/baz');

  andThen(() => {
    const routeHierarchy = componentInstance.get('routeHierarchy');
    assert.equal(currentRouteName(), 'foo.bar.baz.index', 'correct current route name');
    assert.equal(routeHierarchy.length, 3, 'returns correct number of routes');
  });
});

test('routes that opt-out should not be shown', function(assert) {
  assert.expect(2);
  visit('/foo/bar/baz/hidden');

  andThen(() => {
    const routeHierarchy = componentInstance.get('routeHierarchy');
    assert.equal(currentRouteName(), 'foo.bar.baz.hidden', 'correct current route name');
    assert.equal(routeHierarchy.length, 3, 'returns correct number of routes');
  });
});

test('routes can set dynamic breadcrumb properties', function(assert) {
  assert.expect(4);
  visit('/foo/bar/baz/show');

  andThen(() => {
    const routeHierarchy = componentInstance.get('routeHierarchy');
    const routeTitles = map(routeHierarchy, (route) => route.title);
    const routeLooks = map(routeHierarchy, (route) => route.look);
    const hasDynamicTitle = filter(routeTitles, (title) => title === 'Derek Zoolander').length;
    const hasDynamicLook = filter(routeLooks, (look) => look === 'Blue Steel').length;

    assert.equal(currentRouteName(), 'foo.bar.baz.show', 'correct current route name');
    assert.equal(routeHierarchy.length, 4, 'returns correct number of routes');
    assert.ok(hasDynamicTitle, 'returns the correct dynamic title');
    assert.ok(hasDynamicLook, 'returns the correct arbitrary property');
  });
});
<commit_msg>Updated acceptance test for bread-crumbs.<commit_after>import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from '../helpers/start-app';
import {
  lookupComponent,
  lookupRoute
} from '../helpers/lookup';

const {
  EnumerableUtils,
  run
} = Ember;

const {
  map,
  filter
} = EnumerableUtils;

let application;
let componentInstance;

module('Acceptance | ember-crumbly integration test', {
  beforeEach() {
    application = startApp();
    componentInstance = lookupComponent(application, 'bread-crumbs');
  },

  afterEach() {
    componentInstance = null;
    run(application, 'destroy');
  }
});

test('routeHierarchy returns the correct number of routes', function(assert) {
  assert.expect(2);
  visit('/foo/bar/baz');

  andThen(() => {
    const routeHierarchy = componentInstance.get('routeHierarchy');
    assert.equal(currentRouteName(), 'foo.bar.baz.index', 'correct current route name');
    assert.equal(routeHierarchy.length, 3, 'returns correct number of routes');
  });
});

test('routes that opt-out are not  shown', function(assert) {
  assert.expect(2);
  visit('/foo/bar/baz/hidden');

  andThen(() => {
    const routeHierarchy = componentInstance.get('routeHierarchy');
    assert.equal(currentRouteName(), 'foo.bar.baz.hidden', 'correct current route name');
    assert.equal(routeHierarchy.length, 3, 'returns correct number of routes');
  });
});

test('routes can set dynamic breadcrumb props', function(assert) {
  assert.expect(5);
  visit('/foo/bar/baz/show');

  andThen(() => {
    const routeHierarchy = componentInstance.get('routeHierarchy');
    const routeTitles = map(routeHierarchy, (route) => route.title);
    const routeLooks = map(routeHierarchy, (route) => route.look);
    const routeLinkables = map(routeHierarchy, (route) => route.linkable);
    const hasDynamicTitle = filter(routeTitles, (title) => title === 'Derek Zoolander').length;
    const hasDynamicLook = filter(routeLooks, (look) => look === 'Blue Steel').length;
    const hasDynamicLinkable = filter(routeLinkables, (linkable) => linkable === false).length;
    assert.equal(currentRouteName(), 'foo.bar.baz.show', 'correct current route name');
    assert.equal(routeHierarchy.length, 4, 'returns correct number of routes');
    assert.ok(hasDynamicTitle, 'returns the correct title prop');
    assert.ok(hasDynamicLinkable, 'returns the correct linkable prop');
    assert.ok(hasDynamicLook, 'returns the correct arbitrary prop');
  });
});

test('routes that are not linkable do not generate an <a> tag', function(assert) {
  assert.expect(3);
  visit('/foo/bar/baz/');

  andThen(() => {
    const listElementsLength = find('#bootstrapLinkable li').length;
    const listAnchorElementsLength = find('#bootstrapLinkable li a').length;
    assert.equal(currentRouteName(), 'foo.bar.baz.index', 'correct current route name');
    assert.equal(listElementsLength, 3, 'returns the correct number of list elements');
    assert.equal(listAnchorElementsLength, 2, 'returns the correct number of list anchor elements');
  });
});

test('bread-crumbs component outputs the right class', function(assert) {
  assert.expect(3);
  visit('/foo');

  andThen(() => {
    const foundationList = find('#foundationLinkable');
    const bootstrapList = find('#bootstrapLinkable');
    const hasCorrectFoundationClass = foundationList.hasClass('breadcrumbs');
    const hasCorrectBootstrapClass = bootstrapList.hasClass('breadcrumb');
    assert.equal(currentRouteName(), 'foo.index', 'correct current route name');
    assert.ok(hasCorrectFoundationClass, 'returns the correct Foundation class');
    assert.ok(hasCorrectBootstrapClass, 'returns the correct Bootstrap class');
  });
});
<|endoftext|>


<commit_before>//asks to confirm refresh page click event or when F5 is pressed
window.onbeforeunload = function(e) {
	return undefined;
};

$(document).ready(function(){

    loadDefaultSequence();

	$("button.toggle").html("&#x25B2");

    $("button.toggle").click(function(){
    	var $courses =  $(this).parent().parent().children(".courseContainer");

    	if($courses.is(":hidden")){
			$(this).html("&#x25B2");
		}else{
			$(this).html("&#x25BC");
		}

        $courses.slideToggle();
    });

    $("button.search").click(function(){
		// var code = courseList.semesterList[0].courseList[0].code.toString();
		// var name = courseList.semesterList[0].courseList[0].name.toString();
		// var credits = courseList.semesterList[0].courseList[0].credits.toString();
		// var length = courseList.semesterList.length;
		// var $left = $("button.toggle").parent().parent().children(".left");
	});
});

function loadDefaultSequence(){
    var oReq = new XMLHttpRequest();
    oReq.addEventListener("load", function(){

        var courseList = JSON.parse(this.responseText);
        populatePage(courseList);

    });
    oReq.open("GET", "http://138.197.6.26/courseplanner/js/defaultSequence.json");
    oReq.send();
}

function populatePage(courseSequenceObject){
	for(var i = 0; i < courseSequenceObject.semesterList.length; i++){
	    var $courseContainer = $(".scheduleContainer .term:nth-of-type(" + (i + 1) +") .courseContainer");
		if(courseSequenceObject.semesterList[i].courseList.length === 0){
            addCourseRow($courseContainer, "-        ", "Work Term", "-");
		} else {
			for(var j = 0; j < courseSequenceObject.semesterList[i].courseList.length; j++){
				if(courseSequenceObject.semesterList[i].courseList[j].isElective === "true"){
					var electiveType = courseSequenceObject.semesterList[i].courseList[j].electiveType.toString();
                    addCourseRow($courseContainer, "-        ", electiveType + " Elective", "-");
				}else{
					var code = courseSequenceObject.semesterList[i].courseList[j].code.toString();
					var name = courseSequenceObject.semesterList[i].courseList[j].name.toString();
					var credits = courseSequenceObject.semesterList[i].courseList[j].credits.toString();
                    addCourseRow($courseContainer, code, name, credits);
				}
			}
		}
	}

    // add UI event listeners AFTER we've built all the html

    $("div.course").mousedown(function(){
        $(this).addClass("grabbed");
    });

    $("div.course").mouseup(function(){
        $(this).removeClass("grabbed");
    });

    $("div.course").click(function(){
        var code = $(this).find(".left").html();

        if(code !== "-" && code !== ""){
            var requestBody = {
                "code": code
            };

            var oReq = new XMLHttpRequest();
            oReq.addEventListener("load", function(){

                var response = JSON.parse(this.responseText);
                fillCourseInfoBox(response);

            });
            oReq.open("POST", "http://138.197.6.26/courseplanner/courseinfo");
            oReq.send(JSON.stringify(requestBody));

        }
    });

    $(".courseContainer, .semesterHeader").sortable({
        connectWith: ".courseContainer",
        //change event gets called when an item is dragged into a new position (including its original position)
        change: function(event, ui) {
            var centerText = $(ui.item).find(".center").text();
            var index = ui.placeholder.index();
            console.log("Moved an item with center text: " + centerText + " to index: " + index);
        },
        //update event gets invoked when an item is dropped into a new position (excluding its original position)
        update: function(event, ui) {
            console.log("An item has been dropped into a new spot!");
            validateSequence();
        }
    }).disableSelection();
}

function addCourseRow($courseContainer, code, name, credits){
    var rowHtml = "

" + code +"

" + name +"

" + credits +"

";
    $courseContainer.append(rowHtml);
}

function validateSequence(){
    generateSequenceObject( function(result){
        var oReq = new XMLHttpRequest();
        oReq.addEventListener("load", function(){

            var response = JSON.parse(this.responseText);
            console.log("Server validation response: " + this.responseText);

        });
        oReq.open("POST", "http://138.197.6.26/courseplanner/validate");
        oReq.send(JSON.stringify({
            "semesterList": result
        }));
    });
}

function generateSequenceObject(callback){
	var semesterList = [];
	var count = 0;
	var onFinish = function(semesterObject){
        if(semesterObject) {
            semesterList.push(semesterObject);
        }
        count++;
        if(count === 15){
            callback(semesterList);
        }
	};
	for(var i = 1; i <= 15; i++){
		getSemesterObject($(".scheduleContainer .term:nth-of-type(" + i + ")"), onFinish);
	}
}

function getSemesterObject($semesterContainer, callback){
	var seasonText = $semesterContainer.find(".semesterHeading").text().split(" ")[0].trim().toLowerCase();
	var courseList = [];
	var $courses = $semesterContainer.find(".course");
    var count = $courses.length;
    var isWorkTerm = false;
	if(count > 0){
        $courses.each(function(i, obj){
            var courseObject = getCourseObject($(this));
            if(courseObject){
                courseList.push(courseObject);
            } else {
                courseList = [];
                isWorkTerm = true;
            }
            if(i === count-1){
                callback({"season" : seasonText, "courseList": courseList, "isWorkTerm": isWorkTerm});
            }
        });
    } else {
	    // ignore the empty terms by regarding them as undefined
        callback(undefined);
    }
}

function getCourseObject($courseContainer){
    var code = $courseContainer.find(".left").text();
    var name = $courseContainer.find(".center").text();

    if(name.includes("Work Term")){
    	return undefined;
	}

    var credits = $courseContainer.find(".right").text();
	var isElective = $courseContainer.find(".center").text().includes("Elective");
    var electiveType = "";

	if(isElective){
		electiveType = $courseContainer.find(".center").text().replace(" Elective", "");
		code = "";
		name = "";
		credits = "";
	}

	return {
        "code": code,
        "name": name,
        "credits": credits,
        "isElective": isElective,
        "electiveType": electiveType
    };
}

function fillCourseInfoBox(courseInfo){
    var name = courseInfo.name;
    var credits = courseInfo.credits;
    var code = courseInfo.code;
    var notes = courseInfo.notes || "";

    var termsOffered = "";
    if(courseInfo.termsOffered){
        if(courseInfo.termsOffered.includes("f"))
            termsOffered = termsOffered + "fall ";
        if(courseInfo.termsOffered.includes("w"))
            termsOffered = termsOffered + "winter ";
        if(courseInfo.termsOffered.includes("s"))
            termsOffered = termsOffered + "summer ";
    }

    var prereqs = "";
    if(courseInfo.prereqs){
        for(var i = 0; i < courseInfo.prereqs.length; i++){
            prereqs = prereqs + courseInfo.prereqs[i] + ", ";
        }
    }

    var coreqs = "";
    if(courseInfo.coreqs){
        for(var j = 0; j < courseInfo.coreqs.length; j++){
            coreqs = coreqs + courseInfo.coreqs[j] + ", ";
        }
    }

    prereqs = prereqs || "None";
    coreqs = coreqs || "None";
    termsOffered = termsOffered || "None";
    notes = notes || "None";

    $("p.info").html("Prerequisites: " + prereqs + "
" +
        "Corequisites: " + coreqs + "
" +
        "Terms offered: " + termsOffered + "
" +
        "Notes: " + notes);
}

<commit_msg>ensure validate only gets called once per view update<commit_after>//variable used to ensure the schedule is only validated once per view update
var draggingItem = false;

//asks to confirm refresh page click event or when F5 is pressed
window.onbeforeunload = function(e) {
	return undefined;
};

$(document).ready(function(){

    loadDefaultSequence();

	$("button.toggle").html("&#x25B2");

    $("button.toggle").click(function(){
    	var $courses =  $(this).parent().parent().children(".courseContainer");

    	if($courses.is(":hidden")){
			$(this).html("&#x25B2");
		}else{
			$(this).html("&#x25BC");
		}

        $courses.slideToggle();
    });

    $("button.search").click(function(){
		// var code = courseList.semesterList[0].courseList[0].code.toString();
		// var name = courseList.semesterList[0].courseList[0].name.toString();
		// var credits = courseList.semesterList[0].courseList[0].credits.toString();
		// var length = courseList.semesterList.length;
		// var $left = $("button.toggle").parent().parent().children(".left");
	});
});

function loadDefaultSequence(){
    var oReq = new XMLHttpRequest();
    oReq.addEventListener("load", function(){

        var courseList = JSON.parse(this.responseText);
        populatePage(courseList);

    });
    oReq.open("GET", "http://138.197.6.26/courseplanner/js/defaultSequence.json");
    oReq.send();
}

function populatePage(courseSequenceObject){
	for(var i = 0; i < courseSequenceObject.semesterList.length; i++){
	    var $courseContainer = $(".scheduleContainer .term:nth-of-type(" + (i + 1) +") .courseContainer");
		if(courseSequenceObject.semesterList[i].courseList.length === 0){
            addCourseRow($courseContainer, "-        ", "Work Term", "-");
		} else {
			for(var j = 0; j < courseSequenceObject.semesterList[i].courseList.length; j++){
				if(courseSequenceObject.semesterList[i].courseList[j].isElective === "true"){
					var electiveType = courseSequenceObject.semesterList[i].courseList[j].electiveType.toString();
                    addCourseRow($courseContainer, "-        ", electiveType + " Elective", "-");
				}else{
					var code = courseSequenceObject.semesterList[i].courseList[j].code.toString();
					var name = courseSequenceObject.semesterList[i].courseList[j].name.toString();
					var credits = courseSequenceObject.semesterList[i].courseList[j].credits.toString();
                    addCourseRow($courseContainer, code, name, credits);
				}
			}
		}
	}

    // add UI event listeners AFTER we've built all the html

    $("div.course").mousedown(function(){
        $(this).addClass("grabbed");
    });

    $("div.course").mouseup(function(){
        $(this).removeClass("grabbed");
    });

    $("div.course").click(function(){
        var code = $(this).find(".left").html();

        if(code !== "-" && code !== ""){
            var requestBody = {
                "code": code
            };

            var oReq = new XMLHttpRequest();
            oReq.addEventListener("load", function(){

                var response = JSON.parse(this.responseText);
                fillCourseInfoBox(response);

            });
            oReq.open("POST", "http://138.197.6.26/courseplanner/courseinfo");
            oReq.send(JSON.stringify(requestBody));

        }
    });

    $(".courseContainer, .semesterHeader").sortable({
        connectWith: ".courseContainer",
        //change event gets called when an item is dragged into a new position (including its original position)
        change: function(event, ui) {
            var centerText = $(ui.item).find(".center").text();
            var index = ui.placeholder.index();
            draggingItem = true;
            console.log("Moved an item with center text: " + centerText + " to index: " + index);
        },
        //update event gets invoked when an item is dropped into a new position (excluding its original position)
        update: function(event, ui) {
            console.log("An item has been dropped into a new spot!");
            if(draggingItem){
                validateSequence();
            }
            draggingItem = false;
        }
    }).disableSelection();
}

function addCourseRow($courseContainer, code, name, credits){
    var rowHtml = "

" + code +"

" + name +"

" + credits +"

";
    $courseContainer.append(rowHtml);
}

function validateSequence(){
    generateSequenceObject( function(result){
        var oReq = new XMLHttpRequest();
        oReq.addEventListener("load", function(){

            var response = JSON.parse(this.responseText);
            console.log("Server validation response: " + this.responseText);

        });
        oReq.open("POST", "http://138.197.6.26/courseplanner/validate");
        oReq.send(JSON.stringify({
            "semesterList": result
        }));
    });
}

function generateSequenceObject(callback){
	var semesterList = [];
	var count = 0;
	var onFinish = function(semesterObject){
        if(semesterObject) {
            semesterList.push(semesterObject);
        }
        count++;
        if(count === 15){
            callback(semesterList);
        }
	};
	for(var i = 1; i <= 15; i++){
		getSemesterObject($(".scheduleContainer .term:nth-of-type(" + i + ")"), onFinish);
	}
}

function getSemesterObject($semesterContainer, callback){
	var seasonText = $semesterContainer.find(".semesterHeading").text().split(" ")[0].trim().toLowerCase();
	var courseList = [];
	var $courses = $semesterContainer.find(".course");
    var count = $courses.length;
    var isWorkTerm = false;
	if(count > 0){
        $courses.each(function(i, obj){
            var courseObject = getCourseObject($(this));
            if(courseObject){
                courseList.push(courseObject);
            } else {
                courseList = [];
                isWorkTerm = true;
            }
            if(i === count-1){
                callback({"season" : seasonText, "courseList": courseList, "isWorkTerm": isWorkTerm});
            }
        });
    } else {
	    // ignore the empty terms by regarding them as undefined
        callback(undefined);
    }
}

function getCourseObject($courseContainer){
    var code = $courseContainer.find(".left").text();
    var name = $courseContainer.find(".center").text();

    if(name.includes("Work Term")){
    	return undefined;
	}

    var credits = $courseContainer.find(".right").text();
	var isElective = $courseContainer.find(".center").text().includes("Elective");
    var electiveType = "";

	if(isElective){
		electiveType = $courseContainer.find(".center").text().replace(" Elective", "");
		code = "";
		name = "";
		credits = "";
	}

	return {
        "code": code,
        "name": name,
        "credits": credits,
        "isElective": isElective,
        "electiveType": electiveType
    };
}

function fillCourseInfoBox(courseInfo){
    var name = courseInfo.name;
    var credits = courseInfo.credits;
    var code = courseInfo.code;
    var notes = courseInfo.notes || "";

    var termsOffered = "";
    if(courseInfo.termsOffered){
        if(courseInfo.termsOffered.includes("f"))
            termsOffered = termsOffered + "fall ";
        if(courseInfo.termsOffered.includes("w"))
            termsOffered = termsOffered + "winter ";
        if(courseInfo.termsOffered.includes("s"))
            termsOffered = termsOffered + "summer ";
    }

    var prereqs = "";
    if(courseInfo.prereqs){
        for(var i = 0; i < courseInfo.prereqs.length; i++){
            prereqs = prereqs + courseInfo.prereqs[i] + ", ";
        }
    }

    var coreqs = "";
    if(courseInfo.coreqs){
        for(var j = 0; j < courseInfo.coreqs.length; j++){
            coreqs = coreqs + courseInfo.coreqs[j] + ", ";
        }
    }

    prereqs = prereqs || "None";
    coreqs = coreqs || "None";
    termsOffered = termsOffered || "None";
    notes = notes || "None";

    $("p.info").html("Prerequisites: " + prereqs + "
" +
        "Corequisites: " + coreqs + "
" +
        "Terms offered: " + termsOffered + "
" +
        "Notes: " + notes);
}

<|endoftext|>


<commit_before>require("shelljs/global");

var path = require("path");
var fs   = require("fs");

// uninstall global babel install
exec("npm list --global --depth 1 babel >/dev/null 2>&1 && npm uninstall -g babel || true");

// get packages
var packages = [];
ls("packages/*").forEach(function (loc) {
  var name = path.basename(loc);
  if (name[0] === ".") return;

  var pkgLoc = __dirname + "/../packages/" + name + "/package.json";
  if (!fs.existsSync(pkgLoc)) return;

  var pkg = require(pkgLoc);
  packages.push({
    folder: name,
    pkg: pkg,
    name: pkg.name
  });
});

// create links
packages.forEach(function (root) {
  console.log(root.name);

  var nodeModulesLoc = "packages/" + root.folder + "/node_modules";
  mkdir("-p", nodeModulesLoc);

  packages.forEach(function (sub) {
    if (!root.pkg.dependencies || !root.pkg.dependencies[sub.name]) return;

    if (!fs.existsSync(nodeModulesLoc + "/" + sub.name)) {
      console.log("Linking", "packages/" + sub.folder, "to", nodeModulesLoc + "/" + sub.name);
      ln("-s", "packages/" + sub.folder, nodeModulesLoc + "/" + sub.name);
    }
  });

  cd("packages/" + root.folder);
  exec("npm install");
  exec("npm link");
  cd("../..");
});

exec("make build");
<commit_msg>add catch to npm uninstall babel in bootstrap<commit_after>require("shelljs/global");

var path = require("path");
var fs   = require("fs");

// uninstall global babel install
try {
  exec("npm uninstall -g babel");
} catch (err) {}

// get packages
var packages = [];
ls("packages/*").forEach(function (loc) {
  var name = path.basename(loc);
  if (name[0] === ".") return;

  var pkgLoc = __dirname + "/../packages/" + name + "/package.json";
  if (!fs.existsSync(pkgLoc)) return;

  var pkg = require(pkgLoc);
  packages.push({
    folder: name,
    pkg: pkg,
    name: pkg.name
  });
});

// create links
packages.forEach(function (root) {
  console.log(root.name);

  var nodeModulesLoc = "packages/" + root.folder + "/node_modules";
  mkdir("-p", nodeModulesLoc);

  packages.forEach(function (sub) {
    if (!root.pkg.dependencies || !root.pkg.dependencies[sub.name]) return;

    if (!fs.existsSync(nodeModulesLoc + "/" + sub.name)) {
      console.log("Linking", "packages/" + sub.folder, "to", nodeModulesLoc + "/" + sub.name);
      ln("-s", "packages/" + sub.folder, nodeModulesLoc + "/" + sub.name);
    }
  });

  cd("packages/" + root.folder);
  exec("npm install");
  exec("npm link");
  cd("../..");
});

exec("make build");
<|endoftext|>


<commit_before>/*---------------------------------------------------------
 * OpenERP web_gantt
 *---------------------------------------------------------*/
openerp.web_gantt = function (openerp) {
var _t = openerp.web._t;
var QWeb = openerp.web.qweb;

QWeb.add_template('/web_gantt/static/src/xml/web_gantt.xml');
openerp.web.views.add('gantt', 'openerp.web_gantt.GanttView');
openerp.web_gantt.GanttView = openerp.web.View.extend({

init: function(parent, dataset, view_id) {
        this._super(parent);
        this.view_manager = parent || new openerp.web.NullViewManager();
        this.dataset = dataset;
        this.model = dataset.model;
        this.view_id = view_id;
        this.domain = this.dataset.domain || [];
        this.context = this.dataset.context || {};
        this.has_been_loaded = $.Deferred();
    },

    start: function() {
        this._super();
        return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "gantt"}, this.on_loaded);
    },

    on_loaded: function(data) {
        this.fields_view = data,
        this.name =  this.fields_view.arch.attrs.string,
        this.view_id = this.fields_view.view_id,
        this.fields = this.fields_view.fields;

        this.date_start = this.fields_view.arch.attrs.date_start,
        this.date_delay = this.fields_view.arch.attrs.date_delay,
        this.date_stop = this.fields_view.arch.attrs.date_stop,
        this.day_length = this.fields_view.arch.attrs.day_length || 8;

        this.color_field = this.fields_view.arch.attrs.color,
        this.colors = this.fields_view.arch.attrs.colors;

        var level = this.fields_view.arch.children[0];
        this.parent = level.attrs.link,
        this.text = level.children.length ? level.children[0].attrs.name : level.attrs.name;

        if (!this.date_start) {
            return self.do_warn(_t("date_start is not defined "))
        }

        this.$element.html(QWeb.render("GanttView", {'height': $('.oe-application-container').height(), 'width': $('.oe-application-container').width()}));
        this.has_been_loaded.resolve();
    },

    on_project_loaded: function(projects) {

        if(!projects.length) return;
        var self = this,
            started_projects = _.filter(projects, function(res) {
            return res[self.date_start];
        });

        this.database_projects = started_projects;

        if(!self.name) {
            var name = started_projects[0][self.parent];
            self.name = name instanceof Array? name[name.length - 1] : name;
        }

        $.when(this.project_starting_date(), this.get_project_duration(), this.calculate_difference())
            .then(function() {
                if(self.ganttChartControl) {
                    self.ganttChartControl.clearAll();
                    self.$element.find('#GanttView').empty();
                }
            })
            .then(this.group_projects())
            .then(this.generate_projects())
            .then(this.add_tasks())
            .done(this.init_gantt_view());
    },

    generate_projects : function() {
        var projects = this.database_projects,
            self = this;

        this.GanttTasks = [];
        if(this.group_by.length) {
            _.each(this.GroupProject, function(grp, index) {
                self.GanttTasks.push([]);
                _.each(grp, function(g, g_index) {
                    self.GanttTasks[index].push(new GanttTaskInfo(index + '_'+ g_index, g, self.project_start_date, self.total_duration, 100, ""));
                });
//                self.GanttTasks.push(new GanttTaskInfo(index, grp, self.project_start_date, self.total_duration, 100, ""));
            });
        } else {
            this.GanttTasks.push(new GanttTaskInfo(0, self.name, self.project_start_date, self.total_duration, 100, ""));
        }
        this.GanttProjects = new GanttProjectInfo(0, self.name, self.project_start_date);
        return $.Deferred().resolve().promise();
    },

    group_projects: function() {
        var def = $.Deferred(),
            self = this,
            projects = this.database_projects;

        if (!this.group_by.length) return def.resolve().promise();

        this.GroupProject = [];

        _.each(this.group_by, function(group) {
            self.GroupProject.push(
                _.uniq(
                    _.map(_.pluck(projects, group), function(prj) {
                        return prj instanceof Array ? prj[1] : prj;
                    })
                ));
        });
        return def.resolve().promise();
    },

    get_project_duration: function() {

        var self = this,
            projects = this.database_projects;

        this.project_duration = [];

        _.each(projects, function(project, index) {
            if (self.date_stop && project[self.date_stop]) {
                //ToDO
                console.log('TODO for date_stop');
                self.project_duration.push(0);
            } else if(self.date_delay && project[self.date_delay]) {
                self.project_duration.push(project[self.date_delay]);
            } else {
                self.project_duration.push(0);
            }
        });

        this.max_project_duration = _.max(this.project_duration);
        return $.Deferred().resolve().promise();
    },

    calculate_difference: function() {
        var extend_end_date_day = Math.floor(this.max_project_duration / this.day_length),
            extend_end_date_hours = this.max_project_duration % this.day_length;

        this.project_end_date = this.project_end_date.add({days: extend_end_date_day, hours: extend_end_date_hours})

        var DAY = 1000 * 60 * 60 * 24,
            difference = Math.abs(this.project_start_date.getTime() - this.project_end_date.getTime()),
            day = Math.ceil(difference / DAY),
            hour = (difference % DAY)/(1000 * 60 * 60),
            DiffHour = (day * this.day_length) + hour;

        this.total_duration = parseFloat(DiffHour.toFixed(2));
        return $.Deferred().resolve().promise();
    },

    add_tasks: function() {
        var self = this,
            tasks = this.database_projects;
        if (this.group_by.length) {
        }
        else {
            _.each(tasks, function(task, index){
                var name = task[self.text];
                if (task[self.text] instanceof Array) {
                    name = task[self.text][1];
                }
                self.GanttTasks[0].addChildTask(new GanttTaskInfo(task.id, name, self.format_date(task[self.date_start]), self.project_duration[index], 100, ""));
            });
        }
        return $.Deferred().resolve().promise();
    },

    project_starting_date : function() {
        var self = this,
            projects = this.database_projects,
            min_date = _.min(projects, function(prj) {
                return new Date(prj[self.date_start]);
            }),
            max_date = _.max(projects, function(prj) {
                return self.format_date(prj[self.date_start]);
            });

        this.project_end_date =  this.format_date(max_date[self.date_start]);
        if (min_date) this.project_start_date = this.format_date(min_date[self.date_start]);
        else
            this.project_start_date = Date.today();
        return $.Deferred().resolve().promise();
    },

    init_gantt_view: function() {
        var self = this;

        if (this.group_by.length) {
            _.each(this.GanttTasks, function(tasks) {
                _.each(tasks, function(task, index) {
                    self.GanttProjects.addTask(task);
                })
            });
        }
        else {
            _.each(this.GanttTasks, function(tsk, index){
                self.GanttProjects.addTask(tsk);
            });
        }

        var ganttChartControl = this.ganttChartControl = new GanttChart();

        // Setup paths and behavior
        ganttChartControl.setImagePath("/web_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
        ganttChartControl.setEditable(true);
        ganttChartControl.showTreePanel(true);
        ganttChartControl.showContextMenu(false);
        ganttChartControl.showDescTask(true,'d,s-f');
        ganttChartControl.showDescProject(true,'n,d');

        // Load data structure
        ganttChartControl.addProject(this.GanttProjects);

        // Create Gantt control
        ganttChartControl.create('GanttView');

        // Setup Events
        ganttChartControl.attachEvent("onTaskStartDrag", function(task) {
            var task_date = task.getEST();
            if(task_date.getHours()) {
                task_date.set({hour: task_date.getHours(), minute : task_date.getMinutes(), second:0});
            }
        });
        ganttChartControl.attachEvent("onTaskEndResize", function(task) {return self.ResizeTask(task);});
        ganttChartControl.attachEvent("onTaskEndDrag", function(task) {return self.ResizeTask(task);});
        ganttChartControl.attachEvent("onTaskDblClick", function(task) { return self.editTask(task);});
    },

    format_date : function(date) {
        var datetime_regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/,
            date_regex = /^\d\d\d\d-\d\d-\d\d$/,
            time_regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/,
            def = $.Deferred();
        if(date_regex.exec(date)) {
            this.date_format = "yyyy-MM-dd";
        } else if(time_regex.exec(date)) {
            this.date_format = "HH:mm:ss";
        } else {
            this.date_format = "yyyy-MM-dd HH:mm:ss";
        }
        return openerp.web.auto_str_to_date(date);
    },

    ResizeTask: function(task) {

        var event_id = task.getId();

        if(!event_id)
            return this.do_warn(_t("Project can not be resized"));

        var data = {};
        data[this.date_start] = task.getEST().toString(this.date_format);

        if(this.date_stop) {
            var diff = task.getDuration() % this.day_length,
                finished_date = task.getFinishDate().add({hours: diff});
            data[this.date_stop] = finished_date.toString(this.date_format);
        } else {
            data[this.date_delay] = task.getDuration();
        }
        this.dataset
            .write(event_id, data, {})
            .done(function() {
                self.reloadView();
            });
    },

    editTask: function(task) {
        var self = this;
        var event_id = task.getId();
        if(!event_id)
            return false;

        if(event_id) event_id = parseInt(event_id, 10);

        var action_manager = new openerp.web.ActionManager(this);

        var dialog = new openerp.web.Dialog(this, {
            width: 800,
            height: 600,
            buttons : {
                Cancel : function() {
                    $(this).dialog('destroy');
                },
                Save : function() {
                    var form_view = action_manager.inner_viewmanager.views.form.controller;

                    form_view.do_save(function() {
                        self.reloadView();
                    });
                    $(this).dialog('destroy');
                }
            }
        }).start().open();
        action_manager.appendTo(dialog.$element);
        action_manager.do_action({
            res_model : this.dataset.model,
            res_id: event_id,
            views : [[false, 'form']],
            type : 'ir.actions.act_window',
            auto_search : false,
            flags : {
                search_view: false,
                sidebar : false,
                views_switcher : false,
                action_buttons : false,
                pager: false
            }
        });
    },

    reloadView: function() {
       self.on_project_loaded(self.database_projects);
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

    do_search: function (domains, contexts, groupbys) {
        var self = this;
        this.group_by = groupbys;
        $.when(this.has_been_loaded).then(function() {
            self.dataset
                .read_slice([], {
                    domain: domains,
                    context: contexts,
                    group_by: groupbys
                })
                .done(function(projects) {
                    self.on_project_loaded(projects);
                });
        })

    }

});

// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them

};
// vim:et fdc=0 fdl=0:
<commit_msg>[FIX] Add subtask for groupby.<commit_after>/*---------------------------------------------------------
 * OpenERP web_gantt
 *---------------------------------------------------------*/
openerp.web_gantt = function (openerp) {
var _t = openerp.web._t;
var QWeb = openerp.web.qweb;

QWeb.add_template('/web_gantt/static/src/xml/web_gantt.xml');
openerp.web.views.add('gantt', 'openerp.web_gantt.GanttView');
openerp.web_gantt.GanttView = openerp.web.View.extend({

init: function(parent, dataset, view_id) {
        this._super(parent);
        this.view_manager = parent || new openerp.web.NullViewManager();
        this.dataset = dataset;
        this.model = dataset.model;
        this.view_id = view_id;
        this.domain = this.dataset.domain || [];
        this.context = this.dataset.context || {};
        this.has_been_loaded = $.Deferred();
    },

    start: function() {
        this._super();
        return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "gantt"}, this.on_loaded);
    },

    on_loaded: function(data) {
        this.fields_view = data,
        this.name =  this.fields_view.arch.attrs.string,
        this.view_id = this.fields_view.view_id,
        this.fields = this.fields_view.fields;

        this.date_start = this.fields_view.arch.attrs.date_start,
        this.date_delay = this.fields_view.arch.attrs.date_delay,
        this.date_stop = this.fields_view.arch.attrs.date_stop,
        this.day_length = this.fields_view.arch.attrs.day_length || 8;

        this.color_field = this.fields_view.arch.attrs.color,
        this.colors = this.fields_view.arch.attrs.colors;

        var level = this.fields_view.arch.children[0];
        this.parent = level.attrs.link,
        this.text = level.children.length ? level.children[0].attrs.name : level.attrs.name;

        if (!this.date_start) {
            return self.do_warn(_t("date_start is not defined "))
        }

        this.$element.html(QWeb.render("GanttView", {'height': $('.oe-application-container').height(), 'width': $('.oe-application-container').width()}));
        this.has_been_loaded.resolve();
    },

    on_project_loaded: function(projects) {

        if(!projects.length) return;
        var self = this,
            started_projects = _.filter(projects, function(res) {
            return res[self.date_start];
        });

        this.database_projects = started_projects;

        if(!self.name && started_projects.length) {
            var name = started_projects[0][self.parent];
            self.name = name instanceof Array? name[name.length - 1] : name;
        }

        $.when(this.project_starting_date(), this.get_project_duration(), this.calculate_difference())
            .then(function() {
                if(self.ganttChartControl) {
                    self.ganttChartControl.clearAll();
                    self.$element.find('#GanttView').empty();
                }
            })
            .then(this.group_projects())
            .then(this.generate_projects())
            .then(this.add_tasks())
            .done(this.init_gantt_view());
    },

    group_projects: function() {
        var def = $.Deferred(),
            self = this,
            projects = this.database_projects;

        if (!this.group_by.length) return def.resolve().promise();

        this.GroupProject = _.map(this.group_by, function(grp) {
                return _.groupBy(projects, function(prj) {
                    return prj[grp];
                })
            });
        return def.resolve().promise();
    },

    generate_projects : function() {
        var projects = this.database_projects,
            self = this;

        this.GanttTasks = [];
        if(this.group_by.length) {
            _.each(this.GroupProject, function(GrpProject, index) {
                self.GanttTasks.push([]);
                var counter = 0;
                _.each(GrpProject, function(grp, grpindex) {
                    var name = grpindex.split(',');
                    self.GanttTasks[index]
                        .push(new GanttTaskInfo(index + '_' + counter , name[name.length - 1], self.project_start_date, self.total_duration, 100, ""));
                    counter += 1;
                });
            })
        } else {
            this.GanttTasks.push(new GanttTaskInfo(0, self.name, self.project_start_date, self.total_duration, 100, ""));
        }
        this.GanttProjects = new GanttProjectInfo(0, self.name, self.project_start_date);
        return $.Deferred().resolve().promise();
    },

    add_tasks: function() {
        var self = this,
            tasks = this.database_projects;
        if (this.group_by.length) {
            _.each(this.GroupProject, function(grpproject, index) {
                var counter = 0;
                _.each(grpproject, function(prj, gindex) {
                    _.each(prj, function(task, tindex) {
                        var name = task[self.text];
                        if (task[self.text] instanceof Array) {
                            name = task[self.text][1];
                        }
                        self.GanttTasks[index][counter]
                            .addChildTask(new GanttTaskInfo(task.id, name, self.format_date(task[self.date_start]), self.project_duration[index], 100, ""))
                    });
                    counter += 1;
                })
            });
        }
        else {
            _.each(tasks, function(task, index){
                var name = task[self.text];
                if (task[self.text] instanceof Array) {
                    name = task[self.text][1];
                }
                self.GanttTasks[0].addChildTask(new GanttTaskInfo(task.id, name, self.format_date(task[self.date_start]), self.project_duration[index], 100, ""));
            });
        }
        return $.Deferred().resolve().promise();
    },

    get_project_duration: function() {

        var self = this,
            projects = this.database_projects;

        this.project_duration = [];

        _.each(projects, function(project, index) {
            if (self.date_stop && project[self.date_stop]) {
                //ToDO
                console.log('TODO for date_stop');
                self.project_duration.push(0);
            } else if(self.date_delay && project[self.date_delay]) {
                self.project_duration.push(project[self.date_delay]);
            } else {
                self.project_duration.push(0);
            }
        });

        this.max_project_duration = _.max(this.project_duration);
        return $.Deferred().resolve().promise();
    },

    calculate_difference: function() {
        var extend_end_date_day = Math.floor(this.max_project_duration / this.day_length),
            extend_end_date_hours = this.max_project_duration % this.day_length;

        this.project_end_date = this.project_end_date.add({days: extend_end_date_day, hours: extend_end_date_hours})

        var DAY = 1000 * 60 * 60 * 24,
            difference = Math.abs(this.project_start_date.getTime() - this.project_end_date.getTime()),
            day = Math.ceil(difference / DAY),
            hour = (difference % DAY)/(1000 * 60 * 60),
            DiffHour = (day * this.day_length) + hour;

        this.total_duration = parseFloat(DiffHour.toFixed(2));
        return $.Deferred().resolve().promise();
    },

    project_starting_date : function() {
        var self = this,
            projects = this.database_projects,
            min_date = _.min(projects, function(prj) {
                return new Date(prj[self.date_start]);
            }),
            max_date = _.max(projects, function(prj) {
                return self.format_date(prj[self.date_start]);
            });

        this.project_end_date =  this.format_date(max_date[self.date_start]);
        if (min_date) this.project_start_date = this.format_date(min_date[self.date_start]);
        else
            this.project_start_date = Date.today();
        return $.Deferred().resolve().promise();
    },

    init_gantt_view: function() {
        var self = this;

        if (this.group_by.length) {
            _.each(self.GanttTasks, function(tasks, index) {
                _.each(tasks, function(task, tindex) {
                    self.GanttProjects.addTask(task);
                });
            })
        }
        else {
            _.each(this.GanttTasks, function(tsk, index){
                self.GanttProjects.addTask(tsk);
            });
        }

        var ganttChartControl = this.ganttChartControl = new GanttChart();

        // Setup paths and behavior
        ganttChartControl.setImagePath("/web_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
        ganttChartControl.setEditable(true);
        ganttChartControl.showTreePanel(true);
        ganttChartControl.showContextMenu(false);
        ganttChartControl.showDescTask(true,'d,s-f');
        ganttChartControl.showDescProject(true,'n,d');

        // Load data structure
        ganttChartControl.addProject(this.GanttProjects);

        // Create Gantt control
        ganttChartControl.create('GanttView');

        // Setup Events
        ganttChartControl.attachEvent("onTaskStartDrag", function(task) {
            var task_date = task.getEST();
            if(task_date.getHours()) {
                task_date.set({hour: task_date.getHours(), minute : task_date.getMinutes(), second:0});
            }
        });
        ganttChartControl.attachEvent("onTaskEndResize", function(task) {return self.ResizeTask(task);});
        ganttChartControl.attachEvent("onTaskEndDrag", function(task) {return self.ResizeTask(task);});
        ganttChartControl.attachEvent("onTaskDblClick", function(task) { return self.editTask(task);});
    },

    format_date : function(date) {
        var datetime_regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/,
            date_regex = /^\d\d\d\d-\d\d-\d\d$/,
            time_regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/,
            def = $.Deferred();
        if(date_regex.exec(date)) {
            this.date_format = "yyyy-MM-dd";
        } else if(time_regex.exec(date)) {
            this.date_format = "HH:mm:ss";
        } else {
            this.date_format = "yyyy-MM-dd HH:mm:ss";
        }
        return openerp.web.auto_str_to_date(date);
    },

    ResizeTask: function(task) {

        var event_id = task.getId();

        if(!event_id)
            return this.do_warn(_t("Project can not be resized"));

        var data = {};
        data[this.date_start] = task.getEST().toString(this.date_format);

        if(this.date_stop) {
            var diff = task.getDuration() % this.day_length,
                finished_date = task.getFinishDate().add({hours: diff});
            data[this.date_stop] = finished_date.toString(this.date_format);
        } else {
            data[this.date_delay] = task.getDuration();
        }
        this.dataset
            .write(event_id, data, {})
            .done(function() {
                self.reloadView();
            });
    },

    editTask: function(task) {
        var self = this;
        var event_id = task.getId();
        if(!event_id)
            return false;

        if(event_id) event_id = parseInt(event_id, 10);

        var action_manager = new openerp.web.ActionManager(this);

        var dialog = new openerp.web.Dialog(this, {
            width: 800,
            height: 600,
            buttons : {
                Cancel : function() {
                    $(this).dialog('destroy');
                },
                Save : function() {
                    var form_view = action_manager.inner_viewmanager.views.form.controller;

                    form_view.do_save(function() {
                        self.reloadView();
                    });
                    $(this).dialog('destroy');
                }
            }
        }).start().open();
        action_manager.appendTo(dialog.$element);
        action_manager.do_action({
            res_model : this.dataset.model,
            res_id: event_id,
            views : [[false, 'form']],
            type : 'ir.actions.act_window',
            auto_search : false,
            flags : {
                search_view: false,
                sidebar : false,
                views_switcher : false,
                action_buttons : false,
                pager: false
            }
        });
    },

    reloadView: function() {
       self.on_project_loaded(self.database_projects);
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

    do_search: function (domains, contexts, groupbys) {
        var self = this;
        this.group_by = groupbys;
        $.when(this.has_been_loaded).then(function() {
            self.dataset
                .read_slice([], {
                    domain: domains,
                    context: contexts,
                    group_by: groupbys
                })
                .done(function(projects) {
                    self.on_project_loaded(projects);
                });
        })

    }

});

// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them

};
// vim:et fdc=0 fdl=0:
<|endoftext|>


<commit_before>/*---------------------------------------------------------
 * OpenERP web_graph
 *---------------------------------------------------------*/
/*global openerp:true*/
/*global $:true*/
'use strict';

openerp.web_graph = function (instance) {

var _lt = instance.web._lt;
var _t = instance.web._t;

instance.web.views.add('graph', 'instance.web_graph.GraphView');

 /**
  * GraphView view.  It mostly contains two widgets (PivotTable and ChartView)
  * and some data.
  */
instance.web_graph.GraphView = instance.web.View.extend({
    template: 'GraphView',
    display_name: _lt('Graph'),
    view_type: 'graph',
    events: {
        'click .graph_mode_selection li' : function (event) {
            event.preventDefault();
            var self = this,
                mode = event.target.attributes['data-mode'].nodeValue;
            if (mode == 'data') {
                this.chart_view.hide();
                this.pivot_table.show();
            } else {
                this.pivot_table.hide();
                this.get_data().done(function (data) {
                    self.chart_view.draw(data, mode);
                    self.chart_view.show(mode);
                });
            }
        },
    },

    init: function(parent, dataset, view_id, options) {
        this._super(parent, dataset, view_id, options);
        this.pivot_table = new PivotTable(this);
        this.chart_view = new ChartView(this);
        this.x_groups = [];
        this.measure = null;
        this.domain = [];
        this.model = null;

    },

    view_loading: function (fields_view_get) {
        var self = this;
        this.model = new instance.web.Model(fields_view_get.model, {group_by_no_leaf: true});

        // get the default groupbys and measure defined in the field view
        _.each(fields_view_get.arch.children, function (field) {
            if ('name' in field.attrs) {
                if ('operator' in field.attrs) {
                    self.measure = field.attrs.name;
                } else {
                    self.x_groups.push(field.attrs.name);
                }
            }
        });

        this.chart_view.set_measure(this.measure);
        this.pivot_table.appendTo('.graph_pivot');
        this.chart_view.appendTo('.graph_chart');
        this.chart_view.hide();
        this.get_data().done(this.pivot_table.draw);
    },

    get_data: function () {
        var view_fields = this.x_groups.concat(this.measure);

        return query_groups(this.model, view_fields, this.domain, this.x_groups);
    },

    do_search: function (domain, context, group_by) {
        this.domain = new instance.web.CompoundDomain(domain);
    },

    do_show: function () {
        this.do_push_state({});
        return this._super();
    },

});

 /**
  * PivotTable widget.  It displays the data in tabular data and allows the
  * user to drill down and up in the table
  */
var PivotTable = instance.web.Widget.extend({
    template: 'pivot_table',

    show: function () {
        this.$el.css('display', 'block');
    },

    hide: function () {
        this.$el.css('display', 'none');
    },

    draw: function (data) {
        console.log("data",data);
    },
});

 /**
  * ChartView widget.  It displays the data in chart form, using the nvd3
  * library.  Various modes include bar charts, pie charts or line charts.
  */
var ChartView = instance.web.Widget.extend({
    template: 'chart_view',
    measure: null,

    show: function () {
        this.$el.css('display', 'block');
    },

    hide: function () {
        this.$el.css('display', 'none');
    },

    set_measure: function (measure) {
        this.measure = measure;
    },

    draw: function (data, mode) {
        $('.graph_chart').empty();
        $('.graph_chart').append('<svg></svg>');

        switch (mode) {
            case 'bar_chart':
                this.render_bar_chart(data);
                break;
            case 'line_chart':
                this.render_line_chart(data);
                break;
            case 'pie_chart':
                this.render_pie_chart(data);
                break;
        }
    },

    format_data:  function (datapt) {
        var val = datapt.attributes;
        return {
            x: datapt.attributes.value[1],
            y: this.measure ? val.aggregates[this.measure] : val.length,
        };
    },

    render_bar_chart: function (data) {
        var formatted_data = [{
                key: 'Bar chart',
                values: _.map(data, this.format_data.bind(this)),
            }];

        nv.addGraph(function () {
            var chart = nv.models.discreteBarChart()
                .tooltips(false)
                .showValues(true)
                .staggerLabels(true)
                .width(650)
                .height(400);

            d3.select('.graph_chart svg')
                .datum(formatted_data)
                .attr('width', 650)
                .attr('height', 400)
                .call(chart);

            nv.utils.windowResize(chart.update);
            return chart;
        });
    },

    render_line_chart: function (data) {
        var measure_label = (this.measure) ? this.measure : 'Quantity';

        var formatted_data = [{
                key: measure_label,
                values: _.map(data, this.format_data.bind(this))
            }];

        nv.addGraph(function () {
            var chart = nv.models.lineChart()
                .x(function (d,u) { return u; })
                .width(600)
                .height(300)
                .margin({top: 30, right: 20, bottom: 20, left: 60});

            d3.select('.graph_chart svg')
                .attr('width', 600)
                .attr('height', 300)
                .datum(formatted_data)
                .call(chart);

            return chart;
          });
    },

    render_pie_chart: function (data) {
        var formatted_data = _.map(data, this.format_data.bind(this));

        nv.addGraph(function () {
            var chart = nv.models.pieChart()
                .color(d3.scale.category10().range())
                .width(650)
                .height(400);

            d3.select('.graph_chart svg')
                .datum(formatted_data)
                .transition().duration(1200)
                .attr('width', 650)
                .attr('height', 400)
                .call(chart);

            nv.utils.windowResize(chart.update);
            return chart;
        });
    },

});

/**
 * Query the server and return a deferred which will return the data
 * with all the groupbys applied (this is done for now, but the goal
 * is to modify read_group in order to allow eager and lazy groupbys
 */
function query_groups (model, fields, domain, groupbys) {
    return model.query(fields)
        .filter(domain)
        .group_by(groupbys)
        .then(function (results) {
            var non_empty_results = _.filter(results, function (group) {
                return group.attributes.length > 0;
            });
            if (groupbys.length <= 1) {
                return non_empty_results;
            } else {
                var get_subgroups = $.when.apply(null, _.map(non_empty_results, function (result) {
                    var new_domain = result.model._domain;
                    var new_groupings = groupbys.slice(1);
                    return query_groups(model, fields,new_domain, new_groupings).then(function (subgroups) {
                        result.subgroups_data = subgroups;
                    });
                }));
                return get_subgroups.then(function () {
                    return non_empty_results;
                });
            }
        });
}

};
<commit_msg>[FIX] fix a bug preventing hide and show method of chartview widget to function properly (addon web_graph)<commit_after>/*---------------------------------------------------------
 * OpenERP web_graph
 *---------------------------------------------------------*/
/*global openerp:true $:true*/
/*global $:true*/
/*global _:true*/

'use strict';

openerp.web_graph = function (instance) {

var _lt = instance.web._lt;
var _t = instance.web._t;

instance.web.views.add('graph', 'instance.web_graph.GraphView');

 /**
  * GraphView view.  It mostly contains two widgets (PivotTable and ChartView)
  * and some data.
  */
instance.web_graph.GraphView = instance.web.View.extend({
    template: 'GraphView',
    display_name: _lt('Graph'),
    view_type: 'graph',
    events: {
        'click .graph_mode_selection li' : function (event) {
            event.preventDefault();
            var self = this,
                mode = event.target.attributes['data-mode'].nodeValue;
            if (mode == 'data') {
                this.chart_view.hide();
                this.pivot_table.show();
            } else {
                this.pivot_table.hide();
                this.get_data().done(function (data) {
                    self.chart_view.draw(data, mode);
                    self.chart_view.show(mode);
                });
            }
        },
    },

    init: function(parent, dataset, view_id, options) {
        this._super(parent, dataset, view_id, options);
        this.pivot_table = new PivotTable(this);
        this.chart_view = new ChartView(this);
        this.x_groups = [];
        this.measure = null;
        this.domain = [];
        this.model = null;

    },

    view_loading: function (fields_view_get) {
        var self = this;
        this.model = new instance.web.Model(fields_view_get.model, {group_by_no_leaf: true});

        // get the default groupbys and measure defined in the field view
        _.each(fields_view_get.arch.children, function (field) {
            if ('name' in field.attrs) {
                if ('operator' in field.attrs) {
                    self.measure = field.attrs.name;
                } else {
                    self.x_groups.push(field.attrs.name);
                }
            }
        });

        this.chart_view.set_measure(this.measure);
        this.pivot_table.appendTo('.graph_pivot');
        this.chart_view.appendTo('.graph_chart');
        this.chart_view.hide();
        this.get_data().done(this.pivot_table.draw);
    },

    get_data: function () {
        var view_fields = this.x_groups.concat(this.measure);

        return query_groups(this.model, view_fields, this.domain, this.x_groups);
    },

    do_search: function (domain, context, group_by) {
        this.domain = new instance.web.CompoundDomain(domain);
    },

    do_show: function () {
        this.do_push_state({});
        return this._super();
    },

});

 /**
  * PivotTable widget.  It displays the data in tabular data and allows the
  * user to drill down and up in the table
  */
var PivotTable = instance.web.Widget.extend({
    template: 'pivot_table',

    show: function () {
        this.$el.css('display', 'block');
    },

    hide: function () {
        this.$el.css('display', 'none');
    },

    draw: function (data) {
        console.log("data",data);
    },
});

 /**
  * ChartView widget.  It displays the data in chart form, using the nvd3
  * library.  Various modes include bar charts, pie charts or line charts.
  */
var ChartView = instance.web.Widget.extend({
    template: 'chart_view',
    measure: null,

    show: function () {
        $('.graph_chart').css('display', 'block');
    },

    hide: function () {
        $('.graph_chart').css('display', 'none');
    },

    set_measure: function (measure) {
        this.measure = measure;
    },

    draw: function (data, mode) {
        $('.graph_chart').empty();
        $('.graph_chart').append('<svg></svg>');

        switch (mode) {
            case 'bar_chart':
                this.render_bar_chart(data);
                break;
            case 'line_chart':
                this.render_line_chart(data);
                break;
            case 'pie_chart':
                this.render_pie_chart(data);
                break;
        }
    },

    format_data:  function (datapt) {
        var val = datapt.attributes;
        return {
            x: datapt.attributes.value[1],
            y: this.measure ? val.aggregates[this.measure] : val.length,
        };
    },

    render_bar_chart: function (data) {
        var formatted_data = [{
                key: 'Bar chart',
                values: _.map(data, this.format_data.bind(this)),
            }];

        nv.addGraph(function () {
            var chart = nv.models.discreteBarChart()
                .tooltips(false)
                .showValues(true)
                .staggerLabels(true)
                .width(650)
                .height(400);

            d3.select('.graph_chart svg')
                .datum(formatted_data)
                .attr('width', 650)
                .attr('height', 400)
                .call(chart);

            nv.utils.windowResize(chart.update);
            return chart;
        });
    },

    render_line_chart: function (data) {
        var measure_label = (this.measure) ? this.measure : 'Quantity';

        var formatted_data = [{
                key: measure_label,
                values: _.map(data, this.format_data.bind(this))
            }];

        nv.addGraph(function () {
            var chart = nv.models.lineChart()
                .x(function (d,u) { return u; })
                .width(600)
                .height(300)
                .margin({top: 30, right: 20, bottom: 20, left: 60});

            d3.select('.graph_chart svg')
                .attr('width', 600)
                .attr('height', 300)
                .datum(formatted_data)
                .call(chart);

            return chart;
          });
    },

    render_pie_chart: function (data) {
        var formatted_data = _.map(data, this.format_data.bind(this));

        nv.addGraph(function () {
            var chart = nv.models.pieChart()
                .color(d3.scale.category10().range())
                .width(650)
                .height(400);

            d3.select('.graph_chart svg')
                .datum(formatted_data)
                .transition().duration(1200)
                .attr('width', 650)
                .attr('height', 400)
                .call(chart);

            nv.utils.windowResize(chart.update);
            return chart;
        });
    },

});

/**
 * Query the server and return a deferred which will return the data
 * with all the groupbys applied (this is done for now, but the goal
 * is to modify read_group in order to allow eager and lazy groupbys
 */
function query_groups (model, fields, domain, groupbys) {
    return model.query(fields)
        .filter(domain)
        .group_by(groupbys)
        .then(function (results) {
            var non_empty_results = _.filter(results, function (group) {
                return group.attributes.length > 0;
            });
            if (groupbys.length <= 1) {
                return non_empty_results;
            } else {
                var get_subgroups = $.when.apply(null, _.map(non_empty_results, function (result) {
                    var new_domain = result.model._domain;
                    var new_groupings = groupbys.slice(1);
                    return query_groups(model, fields,new_domain, new_groupings).then(function (subgroups) {
                        result.subgroups_data = subgroups;
                    });
                }));
                return get_subgroups.then(function () {
                    return non_empty_results;
                });
            }
        });
}

};
<|endoftext|>


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

    var website = {};
    // The following line can be removed in 2017
    openerp.website = website;

    var templates = website.templates = [
        '/website/static/src/xml/website.xml'
    ];

    website.get_context = function (dict) {
        var html = document.documentElement;
        return _.extend({
            lang: html.getAttribute('lang').replace('-', '_')
        }, dict);
    };

    /* ----- TEMPLATE LOADING ---- */
    website.add_template = function(template) {
        templates.push(template);
    };
    website.load_templates = function(templates) {
        var def = $.Deferred();
        var count = templates.length;

        var dones = _(templates).map(function (t) {
            return new $.Deferred(function (d) {
                openerp.qweb.add_template(t, function(err) {
                    if (err) {
                        d.reject(err);
                    } else {
                        d.resolve();
                    }
                });
            });
        });
        return $.when.apply(null, dones);
    };
    website.reload = function () {
        window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
    };

    var all_ready = null;
    var dom_ready = website.dom_ready = $.Deferred();
    $(dom_ready.resolve);

    website.init_kanban = function ($kanban) {
        $('.js_kanban_col', $kanban).each(function () {
            var $col = $(this);
            var $pagination = $('.pagination', $col);
            if(!$pagination.size()) {
                return;
            }

            var page_count =  $col.data('page_count');
            var scope = $pagination.last().find("li").size()-2;
            var kanban_url_col = $pagination.find("li a:first").attr("href").replace(/[0-9]+$/, '');

            var data = {
                'domain': $col.data('domain'),
                'model': $col.data('model'),
                'template': $col.data('template'),
                'step': $col.data('step'),
                'orderby': $col.data('orderby')
            };

            $pagination.on('click', 'a', function (ev) {
                ev.preventDefault();
                var $a = $(ev.target);
                if($a.parent().hasClass('active')) {
                    return;
                }

                var page = +$a.attr("href").split(",").pop().split('-')[1];
                data['page'] = page;

                $.post('/website/kanban/', data, function (col) {
                    $col.find("> .thumbnail").remove();
                    $pagination.last().before(col);
                });

                var page_start = page - parseInt(Math.floor((scope-1)/2));
                if (page_start < 1 ) page_start = 1;
                var page_end = page_start + (scope-1);
                if (page_end > page_count ) page_end = page_count;

                if (page_end - page_start < scope) {
                    page_start = page_end - scope > 0 ? page_end - scope : 1;
                }

                $pagination.find('li.prev a').attr("href", kanban_url_col+(page-1 > 0 ? page-1 : 1));
                $pagination.find('li.next a').attr("href", kanban_url_col+(page < page_end ? page+1 : page_end));
                for(var i=0; i < scope; i++) {
                    $pagination.find('li:not(.prev):not(.next):eq('+i+') a').attr("href", kanban_url_col+(page_start+i)).html(page_start+i);
                }
                $pagination.find('li.active').removeClass('active');
                $pagination.find('li:has(a[href="'+kanban_url_col+page+'"])').addClass('active');

            });

        });
    };

    /**
     * Returns a deferred resolved when the templates are loaded
     * and the Widgets can be instanciated.
     */
    website.ready = function() {
        if (!all_ready) {
            all_ready = dom_ready.then(function () {
                // TODO: load translations
                return website.load_templates(templates);
            });
        }
        return all_ready;
    };

    dom_ready.then(function () {
        /* ----- PUBLISHING STUFF ---- */
        $('[data-publish]:has(.js_publish_management)').each(function () {
            $(this).attr("data-publish", $(".js_publish_management .btn-success", this).size() ? "on" : 'off');
        });

        $(document).on('click', '.js_publish_management .js_publish_btn', function (e) {
            var $data = $(this).parents(".js_publish_management:first");
            var $btn = $data.find('.btn:first');
            var publish = $btn.hasClass("btn-success");

            $data.toggleClass("css_unpublish css_publish");
            $btn.removeClass("btn-default btn-success");

            openerp.jsonRpc('/website/publish', 'call', {'id': +$data.data('id'), 'object': $data.data('object')})
                .then(function (result) {
                    $btn.toggleClass("btn-default", !result).toggleClass("btn-success", result);
                    $data.toggleClass("css_unpublish", !result).toggleClass("css_publish", result);
                    $data.parents("[data-publish]").attr("data-publish", +result ? 'on' : 'off');
                });
        });

        /* ----- KANBAN WEBSITE ---- */
        $('.js_kanban').each(function () {
            website.init_kanban(this);
        });

    });

    return website;
})();
<commit_msg>[WIP] load translation, mhhh<commit_after>(function() {
    "use strict";

    var website = {};
    // The following line can be removed in 2017
    openerp.website = website;

    var templates = website.templates = [
        '/website/static/src/xml/website.xml'
    ];

    website.get_context = function (dict) {
        var html = document.documentElement;
        return _.extend({
            lang: html.getAttribute('lang').replace('-', '_')
        }, dict);
    };

    /* ----- TEMPLATE LOADING ---- */
    website.add_template = function(template) {
        templates.push(template);
    };
    website.load_templates = function(templates) {
        var def = $.Deferred();
        var count = templates.length;

        var dones = _(templates).map(function (t) {
            return new $.Deferred(function (d) {
                openerp.qweb.add_template(t, function(err) {
                    if (err) {
                        d.reject(err);
                    } else {
                        d.resolve();
                    }
                });
            });
        });
        return $.when.apply(null, dones);
    };
    website.reload = function () {
        window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
    };

    var all_ready = null;
    var dom_ready = website.dom_ready = $.Deferred();
    $(dom_ready.resolve);

    website.init_kanban = function ($kanban) {
        $('.js_kanban_col', $kanban).each(function () {
            var $col = $(this);
            var $pagination = $('.pagination', $col);
            if(!$pagination.size()) {
                return;
            }

            var page_count =  $col.data('page_count');
            var scope = $pagination.last().find("li").size()-2;
            var kanban_url_col = $pagination.find("li a:first").attr("href").replace(/[0-9]+$/, '');

            var data = {
                'domain': $col.data('domain'),
                'model': $col.data('model'),
                'template': $col.data('template'),
                'step': $col.data('step'),
                'orderby': $col.data('orderby')
            };

            $pagination.on('click', 'a', function (ev) {
                ev.preventDefault();
                var $a = $(ev.target);
                if($a.parent().hasClass('active')) {
                    return;
                }

                var page = +$a.attr("href").split(",").pop().split('-')[1];
                data['page'] = page;

                $.post('/website/kanban/', data, function (col) {
                    $col.find("> .thumbnail").remove();
                    $pagination.last().before(col);
                });

                var page_start = page - parseInt(Math.floor((scope-1)/2), 10);
                if (page_start < 1 ) page_start = 1;
                var page_end = page_start + (scope-1);
                if (page_end > page_count ) page_end = page_count;

                if (page_end - page_start < scope) {
                    page_start = page_end - scope > 0 ? page_end - scope : 1;
                }

                $pagination.find('li.prev a').attr("href", kanban_url_col+(page-1 > 0 ? page-1 : 1));
                $pagination.find('li.next a').attr("href", kanban_url_col+(page < page_end ? page+1 : page_end));
                for(var i=0; i < scope; i++) {
                    $pagination.find('li:not(.prev):not(.next):eq('+i+') a').attr("href", kanban_url_col+(page_start+i)).html(page_start+i);
                }
                $pagination.find('li.active').removeClass('active');
                $pagination.find('li:has(a[href="'+kanban_url_col+page+'"])').addClass('active');

            });

        });
    };

    /**
     * Returns a deferred resolved when the templates are loaded
     * and the Widgets can be instanciated.
     */
    website.ready = function() {
        if (!all_ready) {
            var tpl = website.load_templates(templates);
            // var session;
            // var trads = openerp._t.database.load_translations(session, ['website'], website.get_context().lang);
            all_ready = $.when(dom_ready, tpl);
        }
        return all_ready;
    };

    dom_ready.then(function () {
        /* ----- PUBLISHING STUFF ---- */
        $('[data-publish]:has(.js_publish_management)').each(function () {
            $(this).attr("data-publish", $(".js_publish_management .btn-success", this).size() ? "on" : 'off');
        });

        $(document).on('click', '.js_publish_management .js_publish_btn', function (e) {
            var $data = $(this).parents(".js_publish_management:first");
            var $btn = $data.find('.btn:first');
            var publish = $btn.hasClass("btn-success");

            $data.toggleClass("css_unpublish css_publish");
            $btn.removeClass("btn-default btn-success");

            openerp.jsonRpc('/website/publish', 'call', {'id': +$data.data('id'), 'object': $data.data('object')})
                .then(function (result) {
                    $btn.toggleClass("btn-default", !result).toggleClass("btn-success", result);
                    $data.toggleClass("css_unpublish", !result).toggleClass("css_publish", result);
                    $data.parents("[data-publish]").attr("data-publish", +result ? 'on' : 'off');
                });
        });

        /* ----- KANBAN WEBSITE ---- */
        $('.js_kanban').each(function () {
            website.init_kanban(this);
        });

    });

    return website;
})();
<|endoftext|>