<commit_before>'use strict'

// Library for making requests
const request = require('request')
const BigNumber = require('bignumber.js')

// Necessary node libraries to make sia.js emit events
const Util = require('util')
const EventEmitter = require('events')
const nodePath = require('path')

/**
 * SiadWrapper, a closure, initializes siad as a background process and
 * provides functions to interact with it
 * @class SiadWrapper
 */
function SiadWrapper () {
  // siad details with default values
  var settings = {
    detached: false,
    address: 'localhost:9980',
    rpcAddress: ':9981',
    hostAddress: ':9982',
    datadir: nodePath.join(__dirname, '..', 'Sia'),
    path: nodePath.join(__dirname, '..', 'Sia', process.platform === 'win32' ? 'siad.exe' : 'siad')
  }
  // Ensure precision for unit conversions
  BigNumber.config({ DECIMAL_PLACES: 30 })
  BigNumber.config({ EXPONENTIAL_AT: 1e+9 })
  // Unit conversion constants
  const hastingsPerSiacoin = new BigNumber(10).pow(24)

  // Tracks if siad was last known to be running or not
  var running = false
  // Keep reference to `this` to emit events from within contexts where `this`
  // does not point to this class
  var self = this
  // Inherit `EventEmitter` properties
  EventEmitter.call(this)

  /**
   * Relays calls to daemonAPI with the localhost:port address appended
   * @function SiadWrapper#call
   * @param {apiCall} call - function to run if Siad is running
   * @param {apiResponse} callback
   * @returns {object} request call object
   */
  function apiCall (call, callback) {
    // Interpret string-only calls. Will default to 'GET' requests
    if (typeof call === 'string') {
      call = { url: call }
    }

    // Setup request
    call.url = 'http://' + settings.address + call.url
    call.json = true
    call.headers = {
      'User-Agent': 'Sia-Agent'
    }

    // Return the request sent if the user wants to be creative and get more
    // information than what's passed to the callback
    // TODO: Don't understand why the setImmediate is needed, but without it,
    // some calls seem to not return right after another call but eventually do
    // return once another call is made. Some sort of resource blocking is
    // happening
    setImmediate(function () {
      request(call, function (err, response, body) {
        // The error from request should be null if siad is running
        running = !err

        // If siad puts out an error, pass it as first argument to callback
        if (!err && response.statusCode !== 200) {
          err = body
          body = null
        }

        // Return results to callback
        if (callback !== undefined) {
          callback(err, body)
        }
      })
    })
  }

  // Checks whether siad is running on the current address
  function checkIfSiadRunning (callback) {
    return apiCall('/daemon/version', function (err) {
      // There should be no reason this call would error if siad were running
      // and serving requests
      running = !err

      // Return result to callback
      if (callback !== undefined) {
        callback(running)
      }
    })
  }

  /**
   * Checks whether siad is running and runs ones of two callbacks
   * @function SiadWrapper#ifRunning
   * @param {callback} is - called if siad is running
   * @param {callback} not - called if siad is not running
   * @returns {object} request call object
   */
  function ifSiadRunning (is, not) {
    return checkIfSiadRunning(function (running) {
      if (running && is !== undefined) {
        is()
      } else if (not !== undefined) {
        not()
      }
    })
  }

  /**
   * Synchronous way to check if siad is running, may not be up to date
   * @function SiadWrapper#isRunning
   * @returns {boolean} whether siad is running
   */
  function isSiadRunning (callback) {
    return running
  }

  // Polls the siad API until it comes online
  function waitUntilLoaded (callback) {
    return ifSiadRunning(callback, function () {
      setTimeout(function () {
        waitUntilLoaded(callback)
      }, 1000)
    })
  }

  /**
   * Starts the daemon as a long running background process
   * @param {callback} callback - function to be called upon completion.  If start fails, call callback with the error.
   * @returns {boolean} if start was attempted
   */
  function start (callback) {
    // Check if siad is already running
    if (running) {
      if (callback !== null) {
        callback(new Error('Attempted to start siad when it was already running'))
      }
      return false
    }

    // Check synchronously if siad doesn't exist at settings.path
    const fs = require('fs')
    try {
      require('fs').statSync(settings.path)
    } catch (e) {
      if (callback !== null) {
        callback(e)
      }
      return false
    }

    // Set siad folder as configured settings.datadir
    var processOptions = {
      cwd: settings.datadir
    }
    // Set siad's UID to the same as the calling process.
    if (process.geteuid) {
      processOptions.uid = process.geteuid()
    }

    // If the detached option is set, spawn siad as a separate process to be
    // run in the background after the parent process has closed
    if (settings.detached) {
      let log = nodePath.join(settings.datadir, 'out.log')
      let out = fs.openSync(log, 'a')
      let err = fs.openSync(log, 'a')
      processOptions.detached = true
      processOptions.stdio = [ 'ignore', out, err ]
    }

    let daemonProcess
    // Spawn siad
    try {
      const Process = require('child_process').spawn
      daemonProcess = new Process(settings.path, [
        '--api-addr=' + settings.address,
        '--rpc-addr=' + settings.rpcAddress,
        '--host-addr=' + settings.hostAddress,
        '--sia-directory=' + settings.datadir
      ], processOptions)
    } catch (e) {
      if (callback !== null) {
        callback(e)
      }
      return false
    }

    // Exclude it from the parent process' event loop if detached
    if (settings.detached) {
      daemonProcess.unref()
    } else {
      // Listen for siad events and emit them from wrapper
      // TODO: Attach these to siad if it's already running
      var childProcessEvents = ['close', 'disconnect', 'error', 'message']
      childProcessEvents.forEach(function (ev) {
        daemonProcess.on(ev, function (arg1, arg2) {
          self.emit(ev, arg1, arg2)
        })
      })
      // Call callback with an error if 'exit' or 'error' or 'close' is thrown by the child process.
      daemonProcess.on('exit', (code) => {
        running = false
        self.emit('exit', code)
        if (callback !== null) {
          callback(new Error('Siad exited unexpectedly'))
        }
      })
      if (callback !== null) {
        daemonProcess.on('error', (e) => callback(new Error('Siad returned error: ' + e.toString())))
        daemonProcess.on('close', callback(new Error('Siad unexpectedly closed')))
      }
    }

    // Wait until siad finishes loading to call callback
    waitUntilLoaded(callback)
    return true
  }

  /**
   * Sends a stop call to the daemon
   * @param {callback} callback - function to be run if successful
   * @returns {boolean} if stop was attempted, should always be true
   */
  function stop (callback) {
    apiCall('/daemon/stop', function (err) {
      if (!err) {
        running = false
      }
      if (callback !== undefined) {
        callback(err)
      }
    })
    return true
  }

  /**
   * Sets the member variables based on the passed config. Checks if siad is
   * running on the new configuration so running should be up to date for
   * the callback
   * @param {config} c - the config object derived from config.json
   * @param {callback} callback - first argument is any errors, second argument
   * is the new configuration
   * @returns {object} siad configuration object
   */
  function configure (newSettings, callback) {
    for (let key in settings) {
      // Set passed in settings within siad
      if (settings.hasOwnProperty(key) && newSettings.hasOwnProperty(key)) {
        settings[key] = newSettings[key]
      } else if (settings.hasOwnProperty(key)) {
        // Set settings to sync with siad
        newSettings[key] = settings[key]
      }
    }
    if (callback !== undefined) {
      checkIfSiadRunning(function (check) {
        callback(null, settings)
      })
    }
    return settings
  }

  /**
   * Downloads siad and siac to a specified or default location
   * @param {string} path - An optional location of where to download to
   * @param {callback} callback
   * @returns {boolean} if download was started, should always be true
   */
  function download (path, callback) {
    if (typeof path === 'string') {
      settings.path = path
    } else {
      // the first argument is either undefined or the callback
      callback = path
      path = settings.path
    }
    return require('./download.js')(path, callback)
  }

  // Sia unit conversion functions.
  // Convert Hastings (the base unit) to Siacoin.  Use strings as input to avoid precision loss.
  // @param {hastings :string}
  // @return BigNumber
  function hastingsToSiacoins (hastings) {
    const hastingsNumber = new BigNumber(hastings)
    return hastingsNumber.dividedBy(hastingsPerSiacoin)
  }
  // Convert Siacoin to Hastings.  Use strings as input to avoid precision loss.
  // @params {siacoin :string}
  // @return BigNumber
  function siacoinsToHastings (siacoins) {
    const siacoinNumber = new BigNumber(siacoins)
    return siacoinNumber.times(hastingsPerSiacoin)
  }

  // Make certain members public
  this.call = apiCall
  this.ifRunning = ifSiadRunning
  this.isRunning = isSiadRunning
  this.start = start
  this.stop = stop
  this.configure = configure
  this.download = download
  this.siacoinsToHastings = siacoinsToHastings
  this.hastingsToSiacoins = hastingsToSiacoins
}

// Inherit functions from `EventEmitter`'s prototype
Util.inherits(SiadWrapper, EventEmitter)

module.exports = new SiadWrapper()
<commit_msg>wrap callback call with arrow function<commit_after>'use strict'

// Library for making requests
const request = require('request')
const BigNumber = require('bignumber.js')

// Necessary node libraries to make sia.js emit events
const Util = require('util')
const EventEmitter = require('events')
const nodePath = require('path')

/**
 * SiadWrapper, a closure, initializes siad as a background process and
 * provides functions to interact with it
 * @class SiadWrapper
 */
function SiadWrapper () {
  // siad details with default values
  var settings = {
    detached: false,
    address: 'localhost:9980',
    rpcAddress: ':9981',
    hostAddress: ':9982',
    datadir: nodePath.join(__dirname, '..', 'Sia'),
    path: nodePath.join(__dirname, '..', 'Sia', process.platform === 'win32' ? 'siad.exe' : 'siad')
  }
  // Ensure precision for unit conversions
  BigNumber.config({ DECIMAL_PLACES: 30 })
  BigNumber.config({ EXPONENTIAL_AT: 1e+9 })
  // Unit conversion constants
  const hastingsPerSiacoin = new BigNumber(10).pow(24)

  // Tracks if siad was last known to be running or not
  var running = false
  // Keep reference to `this` to emit events from within contexts where `this`
  // does not point to this class
  var self = this
  // Inherit `EventEmitter` properties
  EventEmitter.call(this)

  /**
   * Relays calls to daemonAPI with the localhost:port address appended
   * @function SiadWrapper#call
   * @param {apiCall} call - function to run if Siad is running
   * @param {apiResponse} callback
   * @returns {object} request call object
   */
  function apiCall (call, callback) {
    // Interpret string-only calls. Will default to 'GET' requests
    if (typeof call === 'string') {
      call = { url: call }
    }

    // Setup request
    call.url = 'http://' + settings.address + call.url
    call.json = true
    call.headers = {
      'User-Agent': 'Sia-Agent'
    }

    // Return the request sent if the user wants to be creative and get more
    // information than what's passed to the callback
    // TODO: Don't understand why the setImmediate is needed, but without it,
    // some calls seem to not return right after another call but eventually do
    // return once another call is made. Some sort of resource blocking is
    // happening
    setImmediate(function () {
      request(call, function (err, response, body) {
        // The error from request should be null if siad is running
        running = !err

        // If siad puts out an error, pass it as first argument to callback
        if (!err && response.statusCode !== 200) {
          err = body
          body = null
        }

        // Return results to callback
        if (callback !== undefined) {
          callback(err, body)
        }
      })
    })
  }

  // Checks whether siad is running on the current address
  function checkIfSiadRunning (callback) {
    return apiCall('/daemon/version', function (err) {
      // There should be no reason this call would error if siad were running
      // and serving requests
      running = !err

      // Return result to callback
      if (callback !== undefined) {
        callback(running)
      }
    })
  }

  /**
   * Checks whether siad is running and runs ones of two callbacks
   * @function SiadWrapper#ifRunning
   * @param {callback} is - called if siad is running
   * @param {callback} not - called if siad is not running
   * @returns {object} request call object
   */
  function ifSiadRunning (is, not) {
    return checkIfSiadRunning(function (running) {
      if (running && is !== undefined) {
        is()
      } else if (not !== undefined) {
        not()
      }
    })
  }

  /**
   * Synchronous way to check if siad is running, may not be up to date
   * @function SiadWrapper#isRunning
   * @returns {boolean} whether siad is running
   */
  function isSiadRunning (callback) {
    return running
  }

  // Polls the siad API until it comes online
  function waitUntilLoaded (callback) {
    return ifSiadRunning(callback, function () {
      setTimeout(function () {
        waitUntilLoaded(callback)
      }, 1000)
    })
  }

  /**
   * Starts the daemon as a long running background process
   * @param {callback} callback - function to be called upon completion.  If start fails, call callback with the error.
   * @returns {boolean} if start was attempted
   */
  function start (callback) {
    // Check if siad is already running
    if (running) {
      if (callback !== null) {
        callback(new Error('Attempted to start siad when it was already running'))
      }
      return false
    }

    // Check synchronously if siad doesn't exist at settings.path
    const fs = require('fs')
    try {
      require('fs').statSync(settings.path)
    } catch (e) {
      if (callback !== null) {
        callback(e)
      }
      return false
    }

    // Set siad folder as configured settings.datadir
    var processOptions = {
      cwd: settings.datadir
    }
    // Set siad's UID to the same as the calling process.
    if (process.geteuid) {
      processOptions.uid = process.geteuid()
    }

    // If the detached option is set, spawn siad as a separate process to be
    // run in the background after the parent process has closed
    if (settings.detached) {
      let log = nodePath.join(settings.datadir, 'out.log')
      let out = fs.openSync(log, 'a')
      let err = fs.openSync(log, 'a')
      processOptions.detached = true
      processOptions.stdio = [ 'ignore', out, err ]
    }

    let daemonProcess
    // Spawn siad
    try {
      const Process = require('child_process').spawn
      daemonProcess = new Process(settings.path, [
        '--api-addr=' + settings.address,
        '--rpc-addr=' + settings.rpcAddress,
        '--host-addr=' + settings.hostAddress,
        '--sia-directory=' + settings.datadir
      ], processOptions)
    } catch (e) {
      if (callback !== null) {
        callback(e)
      }
      return false
    }

    // Exclude it from the parent process' event loop if detached
    if (settings.detached) {
      daemonProcess.unref()
    } else {
      // Listen for siad events and emit them from wrapper
      // TODO: Attach these to siad if it's already running
      var childProcessEvents = ['close', 'disconnect', 'error', 'message']
      childProcessEvents.forEach(function (ev) {
        daemonProcess.on(ev, function (arg1, arg2) {
          self.emit(ev, arg1, arg2)
        })
      })
      // Call callback with an error if 'exit' or 'error' or 'close' is thrown by the child process.
      daemonProcess.on('exit', (code) => {
        running = false
        self.emit('exit', code)
        if (callback !== null) {
          callback(new Error('Siad exited unexpectedly'))
        }
      })
      if (callback !== null) {
        daemonProcess.on('error', (e) => callback(new Error('Siad returned error: ' + e.toString())))
        daemonProcess.on('close', () => callback(new Error('Siad unexpectedly closed')))
      }
    }

    // Wait until siad finishes loading to call callback
    waitUntilLoaded(callback)
    return true
  }

  /**
   * Sends a stop call to the daemon
   * @param {callback} callback - function to be run if successful
   * @returns {boolean} if stop was attempted, should always be true
   */
  function stop (callback) {
    apiCall('/daemon/stop', function (err) {
      if (!err) {
        running = false
      }
      if (callback !== undefined) {
        callback(err)
      }
    })
    return true
  }

  /**
   * Sets the member variables based on the passed config. Checks if siad is
   * running on the new configuration so running should be up to date for
   * the callback
   * @param {config} c - the config object derived from config.json
   * @param {callback} callback - first argument is any errors, second argument
   * is the new configuration
   * @returns {object} siad configuration object
   */
  function configure (newSettings, callback) {
    for (let key in settings) {
      // Set passed in settings within siad
      if (settings.hasOwnProperty(key) && newSettings.hasOwnProperty(key)) {
        settings[key] = newSettings[key]
      } else if (settings.hasOwnProperty(key)) {
        // Set settings to sync with siad
        newSettings[key] = settings[key]
      }
    }
    if (callback !== undefined) {
      checkIfSiadRunning(function (check) {
        callback(null, settings)
      })
    }
    return settings
  }

  /**
   * Downloads siad and siac to a specified or default location
   * @param {string} path - An optional location of where to download to
   * @param {callback} callback
   * @returns {boolean} if download was started, should always be true
   */
  function download (path, callback) {
    if (typeof path === 'string') {
      settings.path = path
    } else {
      // the first argument is either undefined or the callback
      callback = path
      path = settings.path
    }
    return require('./download.js')(path, callback)
  }

  // Sia unit conversion functions.
  // Convert Hastings (the base unit) to Siacoin.  Use strings as input to avoid precision loss.
  // @param {hastings :string}
  // @return BigNumber
  function hastingsToSiacoins (hastings) {
    const hastingsNumber = new BigNumber(hastings)
    return hastingsNumber.dividedBy(hastingsPerSiacoin)
  }
  // Convert Siacoin to Hastings.  Use strings as input to avoid precision loss.
  // @params {siacoin :string}
  // @return BigNumber
  function siacoinsToHastings (siacoins) {
    const siacoinNumber = new BigNumber(siacoins)
    return siacoinNumber.times(hastingsPerSiacoin)
  }

  // Make certain members public
  this.call = apiCall
  this.ifRunning = ifSiadRunning
  this.isRunning = isSiadRunning
  this.start = start
  this.stop = stop
  this.configure = configure
  this.download = download
  this.siacoinsToHastings = siacoinsToHastings
  this.hastingsToSiacoins = hastingsToSiacoins
}

// Inherit functions from `EventEmitter`'s prototype
Util.inherits(SiadWrapper, EventEmitter)

module.exports = new SiadWrapper()
<|endoftext|>


<commit_before>AjxpSortable = Class.create(SortableTable, {

	initialize: function($super, oTable, oSortTypes, oTHead) {
		$super(oTable, oSortTypes, oTHead);
		this.addSortType( "NumberK", this.replace8a8 );
		this.addSortType( "NumberKo", this.replace8oa8 );
		this.addSortType( "MyDate", this.replaceDate );
		this.addSortType( "StringDirFile", this.toUpperCase, false, this.splitDirsAndFiles.bind(this) );
	},

	replace8a8: function(str) {
		str = str.toUpperCase();
		var splitstr = "____";
		var ar = str.replace(
			/(([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?)(.*)/,
		 "$1"+splitstr+"$4").split(splitstr);
		var num = Number(ar[0]).valueOf();
		var ml = ar[1].replace(/\s*([KMGB])\s*/, "$1");

		if (ml == "K")
			num *= 1024;
		else if(ml == "M")
			num *= 1024 * 1024;
		else if (ml == "G")
			num *= 1024 * 1024 * 1024;
		else if (ml == "T")
			num *= 1024 * 1024 * 1024 * 1024;
		// B and no prefix

		return num;
	},

	replace8oa8: function(str) {
		str = str.toUpperCase();
		if(str == "-")
		{
			return 0;
		}
		var splitstr = "____";
		var ar = str.replace(
			/(([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?)(.*)/,
		 "$1"+splitstr+"$4").split(splitstr);
		var num = Number(ar[0]).valueOf();
		var ml = ar[1].replace(/\s*(KO|MO|GO|B)\s*/, "$1");

		if (ml == "KO")
			num *= 1024;
		else if(ml == "MO")
			num *= 1024 * 1024;
		else if (ml == "GO")
			num *= 1024 * 1024 * 1024;
		else if (ml == "T")
			num *= 1024 * 1024 * 1024 * 1024;
		// B and no prefix

		return num;
	},

	replaceDate: function(s) {
		var parts1 = s.split(" ");

		var parts = parts1[0].split("/");
		var d = new Date(0);
		d.setFullYear(parts[2]);
		d.setDate(parts[0]);
		d.setMonth(parts[1] - 1);

		var hours = parts1[1].split(":");
		d.setHours(hours[0]);
		d.setMinutes(hours[1]);
		return d.getTime();
	},

	splitDirsAndFiles: function(oRow, nColumn) {
		var s;
		var c = oRow.cells[nColumn];
		if (typeof c.innerText != "undefined")
			s = c.innerText;
		else
			s = this.getInnerText(c);
		if(s[0] == ' ') s = s.substr(1, (s.length-1));
		if(oRow.getAttribute('is_file') == '0'){
			s = '000'+s;
		}
		return s.toUpperCase();
	}

});<commit_msg>fix bug 1870796<commit_after>AjxpSortable = Class.create(SortableTable, {

	initialize: function($super, oTable, oSortTypes, oTHead) {
		$super(oTable, oSortTypes, oTHead);
		this.addSortType( "NumberK", this.replace8a8 );
		this.addSortType( "NumberKo", this.replace8oa8 );
		this.addSortType( "MyDate", this.replaceDate );
		this.addSortType( "StringDirFile", this.toUpperCase, false, this.splitDirsAndFiles.bind(this) );
	},

	replace8a8: function(str) {
		str = str.toUpperCase();
		var splitstr = "____";
		var ar = str.replace(
			/(([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?)(.*)/,
		 "$1"+splitstr+"$4").split(splitstr);
		var num = Number(ar[0]).valueOf();
		var ml = ar[1].replace(/\s*([KMGB])\s*/, "$1");

		if (ml == "K")
			num *= 1024;
		else if(ml == "M")
			num *= 1024 * 1024;
		else if (ml == "G")
			num *= 1024 * 1024 * 1024;
		else if (ml == "T")
			num *= 1024 * 1024 * 1024 * 1024;
		// B and no prefix

		return num;
	},

	replace8oa8: function(str) {
		str = str.toUpperCase();
		if(str == "-")
		{
			return 0;
		}
		var splitstr = "____";
		var ar = str.replace(
			/(([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?)(.*)/,
		 "$1"+splitstr+"$4").split(splitstr);
		var num = Number(ar[0]).valueOf();
		var ml = ar[1].replace(/\s*(KO|MO|GO|T|KB|MB|GB)\s*/, "$1");

		if (ml == "KO" || ml == "KB")
			num *= 1024;
		else if(ml == "MO" || ml == "MB")
			num *= 1024 * 1024;
		else if (ml == "GO" || ml == "GB")
			num *= 1024 * 1024 * 1024;
		else if (ml == "T")
			num *= 1024 * 1024 * 1024 * 1024;
		// B and no prefix

		return num;
	},

	replaceDate: function(s) {
		var parts1 = s.split(" ");

		var parts = parts1[0].split("/");
		var d = new Date(0);
		d.setFullYear(parts[2]);
		d.setDate(parts[0]);
		d.setMonth(parts[1] - 1);

		var hours = parts1[1].split(":");
		d.setHours(hours[0]);
		d.setMinutes(hours[1]);
		return d.getTime();
	},

	splitDirsAndFiles: function(oRow, nColumn) {
		var s;
		var c = oRow.cells[nColumn];
		if (typeof c.innerText != "undefined")
			s = c.innerText;
		else
			s = this.getInnerText(c);
		if(s[0] == ' ') s = s.substr(1, (s.length-1));
		if(oRow.getAttribute('is_file') == '0'){
			s = '000'+s;
		}
		return s.toUpperCase();
	}

});<|endoftext|>


<commit_before>;(function(window, $, undefined) {
    'use strict';

    /*!
     * Tag Model
     */
    function Tag(data) {
        this.text = '';
        this.link = '#';

        // Load the tag's information
        this.load(data);
    }

    Tag.Text = {
        MAX: 10,
        MIN: 2
    };

    Tag.prototype = {
        /*!
         * Method to load
         * \return object
         */
        load: function(data) {
            var self = this;

            if ($.isPlainObject(data) && !$.isEmptyObject(data)) {
                $.each(data, function(prop, value) {
                    if (self.hasOwnProperty(prop) && value != '') {
                        self[prop] = value;
                    }
                });
            }

            if ($.type(data) === 'string' || $.type(data) === 'number' ) {
                self.text = $.trim(data);
            }
        },

        /*!
         * Method to build the single tag jQuery object
         * \return string || null
         */
        buildHTML: function() {
            var self = this,
                html = '';

            if (self.text) {
                html += '';
                html += self.getText() + 'x';
                html += '';

                return html;
            }

            return null;
        },

        /*!
         * Method to set the current link
         * \param string url
         * \param isAbsoluteLink
         * \return object
         */
        setLink: function() {
            var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
            var url = arguments[0] || null;
            var isAbsoluteLink = arguments[1] || false;

            if ($.type(url) !== 'string') {
                throw new Error('Please include a vailid url.');
            }

            if (isAbsoluteLink) {
                if (!regexp.test(url)) {
                    throw new Error('Please include an absolute url.');
                }
            }

            this.link = url;
            return this;
        },

        /*!
         * Method to get the tag's text
         * \return string
         */
        getText: function() {
            // Trim the text
            var text = $.trim(this.text);

            // Limit the text length
            return (text.length > Tag.Text.MAX) ? text.slice(0, (Tag.Text.MAX - 3)) + '...' : text;
        },

        /*!
         * Method to get width of the tag's text
         * \return int
         */
        getTextWidth: function(font) {
            var body = $(document.body),
                textHTML = '' + this.getText() + '',
                textWrap = body.append(textHTML).find('span:last'),
                _font = {
                    'font-family': 'Arial',
                    'font-size': 12
                };

            if (font && $.type(font) === 'object') {
                $.extend(_font, font);
            }

            // Apply font CSS to the text and get the width
            var width = textWrap.css(_font).width();

            // Clean up the temp HTML code.
            body.find('span:last').remove();
            return width;
        }
    }

    var Config, CallMethods, Keys, EventActions;

    // Default settings and classes
    Config = {
        settings: {
            wrapperWidth:      300,
            contentWidth:      260,
            minInputWidth:     60,
            rowHeight:         30,
            numRows:           3,

            // For row width calculation
            tagFontSize:       12,
            tagFontFamily:     'Arial',
            tagPadding:        [0, 5, 0, 5], // top, rgt, btm, lft
            tagBorder:         1,
            tagSpace:          6, // ul li margin-right
            closeSize:         [12, 12], // width, height
            closePadding:      [0, 0, 0, 5], // top, rgt, btm, lft

            placeHolder:       '',

            callUrl:           '',
            callMethod:        '',
            localStore:        false,

            onTagAdded:        $.noop,
            onTagRemoved:      $.noop,
            onSearchCompleted: $.noop
        },

        classes: {
            content:   '.input-tag-content',
            input:     '.input-tag-input',
            searchBtn: '.input-tag-search',
            closeBtn:  '.input-tag-close'
        }
    }

    // Constants
    CallMethods = {
        GET:  'get',
        POST: 'post'
    }

    Keys = {
        DELETE:    8,
        BACKSPACE: 46,
        ENTER:     13,
        UP:        38,
        DOWN:      40
    }

    EventActions = {
        CLICK:   'click',
        DBCLICK: 'dblclick',
        KEYDOWN: 'keydown',
        KEYUP:   'keyup',
        SUBMIT:  'submit'
    }

    // Public methods
    var Methods = {
        /*!
         * Method to import the data to tag object, store it to the data.tags
         * \param array||object source
         * \return void
         */
        importData: function(source) {
            return this.each(function() {
                var self = this,
                    $this = $(this),
                    data = $this.data('taginput') || {},
                    _type = $.type(source);

                if ((_type == 'array' || _type == 'object') && data) {
                    $.each(source, function() {
                        var _tag = new Tag(this);

                        if (!checkTagExist.call(self, _tag.text)) {
                            data.tags.push(new Tag(this));
                        }
                    });

                    renderTagRows.call(this);
                    resetUI.call(this);
                } else {
                    $.error( 'Error occurs' );
                }
            });
        },
        /*!
         * Method to unset the current data
         * \return void
         */
        destory: function() {
            return this.each(function() {
                var $this = $(this);

                // Destory all the data
                $this.removeData('taginput');
            });
        }
    }

    // Private methods
    function init(config) {
        return this.each(function() {
            var $this = $(this),
                data = $this.data('taginput');

            if (!data) {
                $this.data('taginput', {
                    config: $.extend(true, Config, config),
                    tags: [] // Array of Tag objects
                });

                data = $this.data('taginput');
            }

            bindEvents.apply(this);
        });
    }

    function bindEvents() {
        var self = this,
            $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes;

        $this.on(EventActions.CLICK, classes.closeBtn, function(e) {
            deleteTag.call(self, $(this).closest('a').data('text'));
            e.preventDefault();
        });

        $this.on(EventActions.KEYDOWN, classes.input, function(e) {
            var keycode =  e.keyCode ? e.keyCode : e.which;

            // Delete the last tag if user press delete or backspace
            if (keycode === Keys.DELETE || keycode === Keys.BACKSPACE) {
                // Check if the input field is empty
                if (!$(this).val()) {
                    deleteTag.call(self, $(this).prev('ul').find('li:last a').data('text'));
                    e.preventDefault();
                }
            }

            // User hit the enter
            if (keycode === Keys.ENTER) {

            }
        });

        // Test
        $this.on(EventActions.CLICK, classes.searchBtn, function(e) {
            e.preventDefault();
            insertTag.call(self, Math.ceil(Math.random()*9999));
        });
    }

    /*!
     * Method to insert a tag
     * \param string text
     * \return void
     */
    function insertTag(tag) {
        var $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes,
            _tag = new Tag(tag);

        if (_tag.text && !checkTagExist.call(this, _tag.text)) {
            data.tags.push(_tag);
        }

        renderTagRows.call(this);
        resetUI.call(this);
    }

    /*!
     * Method to unset the seleted tag from tags array, then rerender the tags list
     * \param string text
     * \return void
     */
    function deleteTag(text) {
        var $this = $(this),
            data = $this.data('taginput');

        if (text) {
            // Unset the tag
            data.tags = $.grep(data.tags, function(tag) {
                return tag.text != text;
            });

            renderTagRows.call(this);
            resetUI.call(this);
        }
    }

    /*!
     * Method to check if the tag exists
     * \param string text
     * \return bool
     */
    function checkTagExist(text) {
        var $this = $(this),
            data = $this.data('taginput'),
            result = false;

        $.each(data.tags, function() {
            if (this.text == text) {
                result = true;
            }
        });

        return result;
    }

    function resetUI() {
        var $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes,
            settings = data.config.settings,
            $input = $this.find(classes.input),
            $content = $this.find(classes.content),
            currentNumRows = parseInt($this.height() / settings.rowHeight),
            lastRowWidth = $content.find('ul').eq(-1).outerWidth(),
            latestNumRows = $content.find('ul').length || 1;

        // If input field is lower than the last tag row, add the input height to the total height
        if (settings.contentWidth - lastRowWidth < settings.minInputWidth) {
            $input.css('width', '80%');
            latestNumRows++;
        } else {
            $input.css('width', (settings.contentWidth - lastRowWidth)).appendTo($content);
        }

        if (latestNumRows != currentNumRows) {
            $this.animate({ height: (((latestNumRows > settings.numRows) ? settings.numRows : latestNumRows) * settings.rowHeight) }, 200);
        }

        focusInput.call(this);
        //applyStyle.call(this);
    }

    /*!
    * Function to display the tag rows
    * \return void
    */
    function renderTagRows() {
        var $this = $(this),
            data = $this.data('taginput'),
            settings = data.config.settings,
            tagWrapWidth = settings.tagPadding[3] + settings.tagPadding[1] + settings.tagBorder * 2 + settings.tagSpace +
                           settings.closePadding[3] + settings.closePadding[1] + settings.closeSize[0],
            currentRowWidth = 0,
            currentRowEls = [],
            html = '';

        // Remove tag rows
        removeTagRows.call(this);

        if (data.tags.length > 0) {
            $.each(data.tags, function() {
                // Get current tag width and tag HTML
                var _elWidth = this.getTextWidth({ 'font-family': settings.tagFontFamily, 'font-size': settings.tagFontSize }) + tagWrapWidth,
                    _elHtml = this.buildHTML();

                // Add to the current row width
                currentRowWidth += _elWidth;
                currentRowEls.push('
' + _elHtml + '
');

                if (currentRowWidth > settings.contentWidth) {
                    // Remove the current element
                    currentRowEls.pop();

                    // Build the row html
                    html += buildTagRow(currentRowEls);

                    // Reset the row width and elements
                    currentRowWidth = _elWidth;
                    currentRowEls = ['
' + _elHtml + '
'];
                }

                // If current tag is the last element in tags array
                if (this == data.tags[data.tags.length - 1]) {
                    html += buildTagRow(currentRowEls);
                }
            });

            // Display the tag rows to the content
            $this.find(data.config.classes.content).prepend(html);
        }
    }

    function removeTagRows() {
        var $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes;

        $this.find(classes.content).find('ul').remove();
    }

    /*!
     * Method to apply the CSS style
     * \return void
     */
    function applyStyle() {
        var $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes,
            settings = data.config.settings,
            $content = $this.find(classes.content);

        $content.find('li').css({
            'marginRight':  settings.tagSpace
        }).find('a').css({
            'padding':      settings.tagPadding.join('px ') + 'px',
            'border-width': settings.tagBorder
        }).find('span').css({
            'padding':      settings.closePadding.join('px ') + 'px'
        }).find('i').css({
            'width':        settings.closeSize[0],
            'height':       settings.closeSize[1]
        });
    }

     /*!
     * Method to focus to the input field
     * \return void
     */
    function focusInput() {
        var $this = $(this),
            data = $this.data('taginput');

        $this.find(data.config.classes.input).focus();
    }

    /*!
    * Function to generate the single tag row
    * \param object|string tagsHTML
    * \return string
    */
    function buildTagRow(rowHTML) {
        var html = '';

        if ($.type(rowHTML) === 'string') { html = rowHTML; }
        if ($.type(rowHTML) === 'array') { html = rowHTML.join(''); }

        return (html) ? '
' + html + '
' : '';
    }

    /*!
    * Function to save search results to the session storage
    * \param string q
    * \param string|array content
    * \return void
    */
    function saveToLocalStorage(q, content) {
        var key = $.trim(q),
            val = null
            type = $.type(content);

        if (type === 'array' || type === 'object') {
            val = JSON.stringify(content);
        }
        if (type === 'string') {
            val = content;
        }

        if (val) {
            sessionStorage.setItem(key, val);
        }
    };

    $.fn.tagInput = function(method) {
        if (Methods[method]) {
            return Methods[method].apply( this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return init.apply(this, arguments);
        } else {
            $.error( 'Method \'' +  method + '\' does not exist on jQuery.tagInput' );
        }
    }

    /*!
     *TODO
     * Method to search the users
     * \If 'term' exists in the session storage, return the value.
     * \Otherwise we call the api.
     *
     * \param string term
     * \return void
     */
    //function doSearch(term) {
    //    var self = this,
    //        _term = $.trim(term) || null;
    //    var onSearchCompleted = self.config.onSearchCompleted, // Callback function
    //        promised = null; // Deferred object
    //
    //    if (_term) {
    //        // Read the saved the search results from session storage
    //        if (self.config.localStore && (returns = sessionStorage.getItem(_term))) {
    //            promised = function() {
    //                var dfd = new $.Deferred(),
    //                    _users = JSON.parse(returns);
    //
    //                // Cache the array of users obj
    //                self.cacheUsers(_users);
    //
    //                // Resolve the deferred object
    //                dfd.resolve();
    //                return dfd.promise();
    //            }();
    //        } else {
    //            $.ajax({
    //                type: 'POST',
    //                url: self.config.url,
    //                data: { name: "John", location: "Boston" }
    //            });
    //
    //            promised = call.api(self.config.url, { term: _term }, function(data) {
    //                if (data.status.code === 2000 && $.type(data.users) === 'array') {
    //                    // Store it to the sessionStorage
    //                    if (self.config.localStore) {
    //                        self.saveToLocalStorage(_term, data.users);
    //                    }
    //
    //                    // Cache the array of users obj
    //                    self.cacheUsers(data.users);
    //                }
    //            });
    //        }
    //    }
    //
    //    // Callback
    //    promised.done(function() {
    //        // Do callback function
    //        if (onSearchCompleted && $.type(onSearchCompleted) === 'function') {
    //            onSearchCompleted.call(self);
    //        }
    //    });
    //}
})(window, jQuery);

<commit_msg>Remove binded function from seach button<commit_after>;(function(window, $, undefined) {
    'use strict';

    /*!
     * Tag Model
     */
    function Tag(data) {
        this.text = '';
        this.link = '#';

        // Load the tag's information
        this.load(data);
    }

    Tag.Text = {
        MAX: 10,
        MIN: 2
    };

    Tag.prototype = {
        /*!
         * Method to load
         * \return object
         */
        load: function(data) {
            var self = this;

            if ($.isPlainObject(data) && !$.isEmptyObject(data)) {
                $.each(data, function(prop, value) {
                    if (self.hasOwnProperty(prop) && value != '') {
                        self[prop] = value;
                    }
                });
            }

            if ($.type(data) === 'string' || $.type(data) === 'number' ) {
                self.text = $.trim(data);
            }
        },

        /*!
         * Method to build the single tag jQuery object
         * \return string || null
         */
        buildHTML: function() {
            var self = this,
                html = '';

            if (self.text) {
                html += '';
                html += self.getText() + 'x';
                html += '';

                return html;
            }

            return null;
        },

        /*!
         * Method to set the current link
         * \param string url
         * \param isAbsoluteLink
         * \return object
         */
        setLink: function() {
            var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
            var url = arguments[0] || null;
            var isAbsoluteLink = arguments[1] || false;

            if ($.type(url) !== 'string') {
                throw new Error('Please include a vailid url.');
            }

            if (isAbsoluteLink) {
                if (!regexp.test(url)) {
                    throw new Error('Please include an absolute url.');
                }
            }

            this.link = url;
            return this;
        },

        /*!
         * Method to get the tag's text
         * \return string
         */
        getText: function() {
            // Trim the text
            var text = $.trim(this.text);

            // Limit the text length
            return (text.length > Tag.Text.MAX) ? text.slice(0, (Tag.Text.MAX - 3)) + '...' : text;
        },

        /*!
         * Method to get width of the tag's text
         * \return int
         */
        getTextWidth: function(font) {
            var body = $(document.body),
                textHTML = '' + this.getText() + '',
                textWrap = body.append(textHTML).find('span:last'),
                _font = {
                    'font-family': 'Arial',
                    'font-size': 12
                };

            if (font && $.type(font) === 'object') {
                $.extend(_font, font);
            }

            // Apply font CSS to the text and get the width
            var width = textWrap.css(_font).width();

            // Clean up the temp HTML code.
            body.find('span:last').remove();
            return width;
        }
    }

    var Config, CallMethods, Keys, EventActions;

    // Default settings and classes
    Config = {
        settings: {
            wrapperWidth:      300,
            contentWidth:      260,
            minInputWidth:     60,
            rowHeight:         30,
            numRows:           3,

            // For row width calculation
            tagFontSize:       12,
            tagFontFamily:     'Arial',
            tagPadding:        [0, 5, 0, 5], // top, rgt, btm, lft
            tagBorder:         1,
            tagSpace:          6, // ul li margin-right
            closeSize:         [12, 12], // width, height
            closePadding:      [0, 0, 0, 5], // top, rgt, btm, lft

            placeHolder:       '',

            callUrl:           '',
            callMethod:        '',
            localStore:        false,

            onTagAdded:        $.noop,
            onTagRemoved:      $.noop,
            onSearchCompleted: $.noop
        },

        classes: {
            content:   '.input-tag-content',
            input:     '.input-tag-input',
            searchBtn: '.input-tag-search',
            closeBtn:  '.input-tag-close'
        }
    }

    // Constants
    CallMethods = {
        GET:  'get',
        POST: 'post'
    }

    Keys = {
        DELETE:    8,
        BACKSPACE: 46,
        ENTER:     13,
        UP:        38,
        DOWN:      40
    }

    EventActions = {
        CLICK:   'click',
        DBCLICK: 'dblclick',
        KEYDOWN: 'keydown',
        KEYUP:   'keyup',
        SUBMIT:  'submit'
    }

    // Public methods
    var Methods = {
        /*!
         * Method to import the data to tag object, store it to the data.tags
         * \param array||object source
         * \return void
         */
        importData: function(source) {
            return this.each(function() {
                var self = this,
                    $this = $(this),
                    data = $this.data('taginput') || {},
                    _type = $.type(source);

                if ((_type == 'array' || _type == 'object') && data) {
                    $.each(source, function() {
                        var _tag = new Tag(this);

                        if (!checkTagExist.call(self, _tag.text)) {
                            data.tags.push(new Tag(this));
                        }
                    });

                    renderTagRows.call(this);
                    resetUI.call(this);
                } else {
                    $.error( 'Error occurs' );
                }
            });
        },
        /*!
         * Method to unset the current data
         * \return void
         */
        destory: function() {
            return this.each(function() {
                var $this = $(this);

                // Destory all the data
                $this.removeData('taginput');
            });
        }
    }

    // Private methods
    function init(config) {
        return this.each(function() {
            var $this = $(this),
                data = $this.data('taginput');

            if (!data) {
                $this.data('taginput', {
                    config: $.extend(true, Config, config),
                    tags: [] // Array of Tag objects
                });

                data = $this.data('taginput');
            }

            bindEvents.apply(this);
        });
    }

    function bindEvents() {
        var self = this,
            $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes;

        $this.on(EventActions.CLICK, classes.closeBtn, function(e) {
            deleteTag.call(self, $(this).closest('a').data('text'));
            e.preventDefault();
        });

        $this.on(EventActions.KEYDOWN, classes.input, function(e) {
            var keycode =  e.keyCode ? e.keyCode : e.which;

            // Delete the last tag if user press delete or backspace
            if (keycode === Keys.DELETE || keycode === Keys.BACKSPACE) {
                // Check if the input field is empty
                if (!$(this).val()) {
                    deleteTag.call(self, $(this).prev('ul').find('li:last a').data('text'));
                    e.preventDefault();
                }
            }

            // User hit the enter
            if (keycode === Keys.ENTER) {

            }
        });

        $this.on(EventActions.CLICK, classes.searchBtn, function(e) {
            e.preventDefault();
        });
    }

    /*!
     * Method to insert a tag
     * \param string text
     * \return void
     */
    function insertTag(tag) {
        var $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes,
            _tag = new Tag(tag);

        if (_tag.text && !checkTagExist.call(this, _tag.text)) {
            data.tags.push(_tag);
        }

        renderTagRows.call(this);
        resetUI.call(this);
    }

    /*!
     * Method to unset the seleted tag from tags array, then rerender the tags list
     * \param string text
     * \return void
     */
    function deleteTag(text) {
        var $this = $(this),
            data = $this.data('taginput');

        if (text) {
            // Unset the tag
            data.tags = $.grep(data.tags, function(tag) {
                return tag.text != text;
            });

            renderTagRows.call(this);
            resetUI.call(this);
        }
    }

    /*!
     * Method to check if the tag exists
     * \param string text
     * \return bool
     */
    function checkTagExist(text) {
        var $this = $(this),
            data = $this.data('taginput'),
            result = false;

        $.each(data.tags, function() {
            if (this.text == text) {
                result = true;
            }
        });

        return result;
    }

    function resetUI() {
        var $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes,
            settings = data.config.settings,
            $input = $this.find(classes.input),
            $content = $this.find(classes.content),
            currentNumRows = parseInt($this.height() / settings.rowHeight),
            lastRowWidth = $content.find('ul').eq(-1).outerWidth(),
            latestNumRows = $content.find('ul').length || 1;

        // If input field is lower than the last tag row, add the input height to the total height
        if (settings.contentWidth - lastRowWidth < settings.minInputWidth) {
            $input.css('width', '80%');
            latestNumRows++;
        } else {
            $input.css('width', (settings.contentWidth - lastRowWidth)).appendTo($content);
        }

        if (latestNumRows != currentNumRows) {
            $this.animate({ height: (((latestNumRows > settings.numRows) ? settings.numRows : latestNumRows) * settings.rowHeight) }, 200);
        }

        focusInput.call(this);
        //applyStyle.call(this);
    }

    /*!
    * Function to display the tag rows
    * \return void
    */
    function renderTagRows() {
        var $this = $(this),
            data = $this.data('taginput'),
            settings = data.config.settings,
            tagWrapWidth = settings.tagPadding[3] + settings.tagPadding[1] + settings.tagBorder * 2 + settings.tagSpace +
                           settings.closePadding[3] + settings.closePadding[1] + settings.closeSize[0],
            currentRowWidth = 0,
            currentRowEls = [],
            html = '';

        // Remove tag rows
        removeTagRows.call(this);

        if (data.tags.length > 0) {
            $.each(data.tags, function() {
                // Get current tag width and tag HTML
                var _elWidth = this.getTextWidth({ 'font-family': settings.tagFontFamily, 'font-size': settings.tagFontSize }) + tagWrapWidth,
                    _elHtml = this.buildHTML();

                // Add to the current row width
                currentRowWidth += _elWidth;
                currentRowEls.push('
' + _elHtml + '
');

                if (currentRowWidth > settings.contentWidth) {
                    // Remove the current element
                    currentRowEls.pop();

                    // Build the row html
                    html += buildTagRow(currentRowEls);

                    // Reset the row width and elements
                    currentRowWidth = _elWidth;
                    currentRowEls = ['
' + _elHtml + '
'];
                }

                // If current tag is the last element in tags array
                if (this == data.tags[data.tags.length - 1]) {
                    html += buildTagRow(currentRowEls);
                }
            });

            // Display the tag rows to the content
            $this.find(data.config.classes.content).prepend(html);
        }
    }

    function removeTagRows() {
        var $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes;

        $this.find(classes.content).find('ul').remove();
    }

    /*!
     * Method to apply the CSS style
     * \return void
     */
    function applyStyle() {
        var $this = $(this),
            data = $this.data('taginput'),
            classes = data.config.classes,
            settings = data.config.settings,
            $content = $this.find(classes.content);

        $content.find('li').css({
            'marginRight':  settings.tagSpace
        }).find('a').css({
            'padding':      settings.tagPadding.join('px ') + 'px',
            'border-width': settings.tagBorder
        }).find('span').css({
            'padding':      settings.closePadding.join('px ') + 'px'
        }).find('i').css({
            'width':        settings.closeSize[0],
            'height':       settings.closeSize[1]
        });
    }

     /*!
     * Method to focus to the input field
     * \return void
     */
    function focusInput() {
        var $this = $(this),
            data = $this.data('taginput');

        $this.find(data.config.classes.input).focus();
    }

    /*!
    * Function to generate the single tag row
    * \param object|string tagsHTML
    * \return string
    */
    function buildTagRow(rowHTML) {
        var html = '';

        if ($.type(rowHTML) === 'string') { html = rowHTML; }
        if ($.type(rowHTML) === 'array') { html = rowHTML.join(''); }

        return (html) ? '
' + html + '
' : '';
    }

    /*!
    * Function to save search results to the session storage
    * \param string q
    * \param string|array content
    * \return void
    */
    function saveToLocalStorage(q, content) {
        var key = $.trim(q),
            val = null
            type = $.type(content);

        if (type === 'array' || type === 'object') {
            val = JSON.stringify(content);
        }
        if (type === 'string') {
            val = content;
        }

        if (val) {
            sessionStorage.setItem(key, val);
        }
    };

    $.fn.tagInput = function(method) {
        if (Methods[method]) {
            return Methods[method].apply( this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return init.apply(this, arguments);
        } else {
            $.error( 'Method \'' +  method + '\' does not exist on jQuery.tagInput' );
        }
    }

    /*!
     *TODO
     * Method to search the users
     * \If 'term' exists in the session storage, return the value.
     * \Otherwise we call the api.
     *
     * \param string term
     * \return void
     */
    //function doSearch(term) {
    //    var self = this,
    //        _term = $.trim(term) || null;
    //    var onSearchCompleted = self.config.onSearchCompleted, // Callback function
    //        promised = null; // Deferred object
    //
    //    if (_term) {
    //        // Read the saved the search results from session storage
    //        if (self.config.localStore && (returns = sessionStorage.getItem(_term))) {
    //            promised = function() {
    //                var dfd = new $.Deferred(),
    //                    _users = JSON.parse(returns);
    //
    //                // Cache the array of users obj
    //                self.cacheUsers(_users);
    //
    //                // Resolve the deferred object
    //                dfd.resolve();
    //                return dfd.promise();
    //            }();
    //        } else {
    //            $.ajax({
    //                type: 'POST',
    //                url: self.config.url,
    //                data: { name: "John", location: "Boston" }
    //            });
    //
    //            promised = call.api(self.config.url, { term: _term }, function(data) {
    //                if (data.status.code === 2000 && $.type(data.users) === 'array') {
    //                    // Store it to the sessionStorage
    //                    if (self.config.localStore) {
    //                        self.saveToLocalStorage(_term, data.users);
    //                    }
    //
    //                    // Cache the array of users obj
    //                    self.cacheUsers(data.users);
    //                }
    //            });
    //        }
    //    }
    //
    //    // Callback
    //    promised.done(function() {
    //        // Do callback function
    //        if (onSearchCompleted && $.type(onSearchCompleted) === 'function') {
    //            onSearchCompleted.call(self);
    //        }
    //    });
    //}
})(window, jQuery);

<|endoftext|>


<commit_before>angular.module("umbraco").controller("Our.Umbraco.DocTypeGridEditor.GridEditors.DocTypeGridEditor", [

    "$scope",
    "$rootScope",
    "$timeout",
    "editorState",
    'assetsService',
    "Our.Umbraco.DocTypeGridEditor.Resources.DocTypeGridEditorResources",
    "umbRequestHelper",
    "localizationService",
    "editorService",

    function ($scope, $rootScope, $timeout, editorState, assetsService, dtgeResources, umbRequestHelper, localizationService, editorService) {

        var overlayOptions = {
            view: umbRequestHelper.convertVirtualToAbsolutePath(
                "~/App_Plugins/DocTypeGridEditor/Views/doctypegrideditor.dialog.html"),
            model: {},
            titles: {
                insertItem: "Click to insert item",
                editItem: "Edit item",
                selectContentType: "Choose a Content Type",
                selectBlueprint: "Choose a Content Template"
            },
            title: "Edit item",
            submitButtonlabelKey: "bulk_done"
        };

        $scope.icon = "icon-item-arrangement";

        // init cached content types if it doesnt exist.
        if (!$rootScope.dtgeContentTypes) $rootScope.dtgeContentTypes = {};

        // localize strings
        localizationService.localizeMany(["docTypeGridEditor_insertItem", "docTypeGridEditor_editItem", "docTypeGridEditor_selectContentType", "blueprints_selectBlueprint"]).then(function (data) {
            overlayOptions.titles.insertItem = data[0];
            overlayOptions.titles.editItem = data[1];
            overlayOptions.titles.selectContentType = data[2];
            overlayOptions.titles.selectBlueprint = data[3];
        });

        $scope.setValue = function (data, callback) {
            $scope.title = $scope.control.editor.name;
            $scope.icon = $scope.control.editor.icon;
            $scope.control.value = data;

            if (!("id" in $scope.control.value) || $scope.control.value.id == "") {
                $scope.control.value.id = guid();
            }
            if ("name" in $scope.control.value.value && $scope.control.value.value.name) {
                $scope.title = $scope.control.value.value.name;
            }
            if ("dtgeContentTypeAlias" in $scope.control.value && $scope.control.value.dtgeContentTypeAlias) {
                if (!$rootScope.dtgeContentTypes[$scope.control.value.dtgeContentTypeAlias]) {

                    dtgeResources.getContentType($scope.control.value.dtgeContentTypeAlias).then(function (data2) {
                        var contentType = {
                            title: data2.title,
                            description: data2.description,
                            icon: data2.icon
                        };

                        // save to cached content types
                        $rootScope.dtgeContentTypes[$scope.control.value.dtgeContentTypeAlias] = contentType;
                        $scope.setTitleAndDescription(contentType);
                    });
                }
                else {
                    $scope.setTitleAndDescription($rootScope.dtgeContentTypes[$scope.control.value.dtgeContentTypeAlias]);
                }
            }
            if (callback)
                callback();
        };

        $scope.setTitleAndDescription = function (contentType) {
            $scope.title = contentType.title;
            $scope.description = contentType.description;
            $scope.icon = contentType.icon;
        };

        $scope.setDocType = function () {

            overlayOptions.editorName = $scope.control.editor.name;
            overlayOptions.allowedDocTypes = $scope.control.editor.config.allowedDocTypes || [];
            overlayOptions.showDocTypeSelectAsGrid = $scope.control.editor.config.showDocTypeSelectAsGrid === true;
            overlayOptions.nameTemplate = $scope.control.editor.config.nameTemplate;
            overlayOptions.size = $scope.control.editor.config.largeDialog ? null : $scope.control.editor.config.overlaySize || "small";

            overlayOptions.dialogData = {
                docTypeAlias: $scope.control.value.dtgeContentTypeAlias,
                value: $scope.control.value.value,
                id: $scope.control.value.id
            };
            overlayOptions.close = function () {
                // ensure an empty doctype is not persisted
                if($scope.control.$initializing){
                    $scope.removeControl($scope.area, $scope.control.$index -1);
                }

                editorService.close();
            }
            overlayOptions.submit = function (newModel) {

                        // Copy property values to scope model value
                        if (newModel.node) {
                            var value = {
                                name: newModel.editorName
                            };

                            for (var v = 0; v < newModel.node.variants.length; v++) {
                                var variant = newModel.node.variants[v];
                                for (var t = 0; t < variant.tabs.length; t++) {
                                    var tab = variant.tabs[t];
                                    for (var p = 0; p < tab.properties.length; p++) {
                                        var prop = tab.properties[p];
                                        if (typeof prop.value !== "function") {
                                            value[prop.alias] = prop.value;
                                        }
                                    }
                                }
                            }

                            if (newModel.nameExp) {
                                var newName = newModel.nameExp(value); // Run it against the stored dictionary value, NOT the node object
                                if (newName && (newName = $.trim(newName))) {
                                    value.name = newName;
                                }
                            }

                            newModel.dialogData.value = value;
                        } else {
                            newModel.dialogData.value = null;

                        }

                        $scope.setValue({
                            dtgeContentTypeAlias: newModel.dialogData.docTypeAlias,
                            value: newModel.dialogData.value,
                            id: newModel.dialogData.id
                        });
                        $scope.setPreview($scope.control.value);
                        editorService.close();
            };

            editorService.open(overlayOptions);
        };

        $scope.setPreview = function (model) {
            if ($scope.control.editor.config && "enablePreview" in $scope.control.editor.config && $scope.control.editor.config.enablePreview) {
                dtgeResources.getEditorMarkupForDocTypePartial(editorState.current.id, model.id,
                    $scope.control.editor.alias, model.dtgeContentTypeAlias, model.value,
                    $scope.control.editor.config.viewPath,
                    $scope.control.editor.config.previewViewPath,
                    !!editorState.current.publishDate)
                    .then(function (response) {
                        var htmlResult = response.data;
                        if (htmlResult.trim().length > 0) {
                            $scope.preview = htmlResult;
                        }
                    });
            }
        };

        function init() {
            $timeout(function () {
                if ($scope.control.$initializing) {
                    $scope.setDocType();
                } else if ($scope.control.value) {
                    $scope.setPreview($scope.control.value);
                }
            }, 200);
        }

        if ($scope.control.value) {
            if (!$scope.control.value.dtgeContentTypeAlias && $scope.control.value.docType) {
                $scope.control.value.dtgeContentTypeAlias = $scope.control.value.docType;
            }
            if ($scope.control.value.docType) {
                delete $scope.control.value.docType;
            }
            if (isGuid($scope.control.value.dtgeContentTypeAlias)) {
                dtgeResources.getContentTypeAliasByGuid($scope.control.value.dtgeContentTypeAlias).then(function (data1) {
                    $scope.control.value.dtgeContentTypeAlias = data1.alias;
                    $scope.setValue($scope.control.value, init);
                });
            } else {
                $scope.setValue($scope.control.value, init);
            }
        } else {
            $scope.setValue({
                id: guid(),
                dtgeContentTypeAlias: "",
                value: {}
            }, init);
        }

        // Load preview css / js files
        if ($scope.control.editor.config && "enablePreview" in $scope.control.editor.config && $scope.control.editor.config.enablePreview) {
            if ("previewCssFilePath" in $scope.control.editor.config && $scope.control.editor.config.previewCssFilePath) {
                assetsService.loadCss($scope.control.editor.config.previewCssFilePath, $scope);
            };

            if ("previewJsFilePath" in $scope.control.editor.config && $scope.control.editor.config.previewJsFilePath) {
                assetsService.loadJs($scope.control.editor.config.previewJsFilePath, $scope);
            }
        }

        function guid() {
            function s4() {
                return Math.floor((1 + Math.random()) * 0x10000)
                    .toString(16)
                    .substring(1);
            }
            return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
                s4() + '-' + s4() + s4() + s4();
        }

        function isGuid(input) {
            return new RegExp("^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$", "i").test(input.toString());
        }

    }
]);

angular.module("umbraco").controller("Our.Umbraco.DocTypeGridEditor.Dialogs.DocTypeGridEditorDialog",
    [
        "$scope",
        "$interpolate",
        "formHelper",
        "contentResource",
        "Our.Umbraco.DocTypeGridEditor.Resources.DocTypeGridEditorResources",
        "Our.Umbraco.DocTypeGridEditor.Services.DocTypeGridEditorUtilityService",
        "blueprintConfig",
        "contentEditingHelper",
        "serverValidationManager",

        function ($scope, $interpolate, formHelper, contentResource, dtgeResources, dtgeUtilityService, blueprintConfig, contentEditingHelper, serverValidationManager) {

            var vm = this;
            vm.submit = submit;
            vm.close = close;
            vm.loading = true;
            vm.blueprintConfig = blueprintConfig;

            function cleanup() {
                if ($scope.model.node.id > 0){
                    // delete any temporary blueprints used for validation
                    contentResource.deleteBlueprint($scope.model.node.id);
                }

                //clear server validation messages when this editor is destroyed
                serverValidationManager.clear();
            }

            $scope.$on('$destroy', cleanup);

            function submit() {
                if ($scope.model.submit) {
                    $scope.model.node.name = $scope.model.node.key;
                    $scope.model.node.variants[0].name = "Dtge Temp: " + $scope.model.node.name
                    $scope.model.node.variants[0].save = true;

                    // save the content as a blueprint, to trigger validation
                    var args = {
                        saveMethod: contentResource.saveBlueprint,
                        scope: $scope,
                        content: $scope.model.node,
                        create: true,
                        action: "save",
                        showNotifications: true,
                        softRedirect: true
                    }

                    contentEditingHelper.contentEditorPerformSave(args).then(function (data) {
                            $scope.model.submit($scope.model);
                        },
                        function (err) {

                        });
                }
            }
            function close() {
                if ($scope.model.close) {
                    $scope.model.close();
                }
            }

            $scope.docTypes = [];
            $scope.dialogMode = null;
            $scope.selectedDocType = null;
            $scope.model.node = null;

            var nameExp = !!$scope.model.nameTemplate
                ? $interpolate($scope.model.nameTemplate)
                : undefined;

            $scope.model.nameExp = nameExp;

            function createBlank() {
                $scope.dialogMode = "edit";
                loadNode();
            };

            function createOrSelectBlueprintIfAny(docType) {

                $scope.model.dialogData.docTypeAlias = docType.alias;
                var blueprintIds = _.keys(docType.blueprints || {});
                $scope.selectedDocType = docType;

                if (blueprintIds.length) {
                    if (blueprintConfig.skipSelect) {
                        createFromBlueprint(blueprintIds[0]);
                    } else {
                        $scope.dialogMode = "selectBlueprint";
                    }
                } else {
                    createBlank();
                }
            };

            function createFromBlueprint(blueprintId) {
                contentResource.getBlueprintScaffold(-1, blueprintId).then(function (data) {
                    // Assign the model to scope
                    $scope.nodeContext = $scope.model.node = data;
                    $scope.dialogMode = "edit";
                    vm.content = $scope.nodeContext.variants[0];
                    vm.loading = false;
                });
            };

            $scope.createBlank = createBlank;
            $scope.createOrSelectBlueprintIfAny = createOrSelectBlueprintIfAny;
            $scope.createFromBlueprint = createFromBlueprint;

            function loadNode() {
                vm.loading = true;
                contentResource.getScaffold(-1, $scope.model.dialogData.docTypeAlias).then(function (data) {

                    // Merge current value
                    if ($scope.model.dialogData.value) {
                        for (var v = 0; v < data.variants.length; v++) {
                            var variant = data.variants[v];
                            for (var t = 0; t < variant.tabs.length; t++) {
                                var tab = variant.tabs[t];
                                for (var p = 0; p < tab.properties.length; p++) {
                                    var prop = tab.properties[p];
                                    if ($scope.model.dialogData.value[prop.alias]) {
                                        prop.value = $scope.model.dialogData.value[prop.alias];
                                    }
                                }
                            }
                        }
                    };

                    // Assign the model to scope
                    $scope.nodeContext = $scope.model.node = data;
                    vm.content = $scope.nodeContext.variants[0];
                    vm.loading = false;
                });
            }

            if ($scope.model.dialogData.docTypeAlias) {
                $scope.dialogMode = "edit";
                loadNode();
            } else {
                $scope.dialogMode = "selectDocType";
                // No data type, so load a list to choose from
                dtgeResources.getContentTypes($scope.model.allowedDocTypes).then(function (docTypes) {
                    $scope.docTypes = docTypes;
                    if ($scope.docTypes.length == 1) {
                        createOrSelectBlueprintIfAny($scope.docTypes[0]);
                    }
                    else {
                        vm.loading = false;
                    }
                });
            }

        }

    ]);
<commit_msg>Fix naming<commit_after>angular.module("umbraco").controller("Our.Umbraco.DocTypeGridEditor.GridEditors.DocTypeGridEditor", [

    "$scope",
    "$rootScope",
    "$timeout",
    "editorState",
    'assetsService',
    "Our.Umbraco.DocTypeGridEditor.Resources.DocTypeGridEditorResources",
    "umbRequestHelper",
    "localizationService",
    "editorService",

    function ($scope, $rootScope, $timeout, editorState, assetsService, dtgeResources, umbRequestHelper, localizationService, editorService) {

        var overlayOptions = {
            view: umbRequestHelper.convertVirtualToAbsolutePath(
                "~/App_Plugins/DocTypeGridEditor/Views/doctypegrideditor.dialog.html"),
            model: {},
            titles: {
                insertItem: "Click to insert item",
                editItem: "Edit item",
                selectContentType: "Choose a Content Type",
                selectBlueprint: "Choose a Content Template"
            },
            title: "Edit item",
            submitButtonlabelKey: "bulk_done"
        };

        $scope.icon = "icon-item-arrangement";

        // init cached content types if it doesnt exist.
        if (!$rootScope.dtgeContentTypes) $rootScope.dtgeContentTypes = {};

        // localize strings
        localizationService.localizeMany(["docTypeGridEditor_insertItem", "docTypeGridEditor_editItem", "docTypeGridEditor_selectContentType", "blueprints_selectBlueprint"]).then(function (data) {
            overlayOptions.titles.insertItem = data[0];
            overlayOptions.titles.editItem = data[1];
            overlayOptions.titles.selectContentType = data[2];
            overlayOptions.titles.selectBlueprint = data[3];
        });

        $scope.setValue = function (data, callback) {
            $scope.title = $scope.control.editor.name;
            $scope.icon = $scope.control.editor.icon;
            $scope.control.value = data;

            if (!("id" in $scope.control.value) || $scope.control.value.id == "") {
                $scope.control.value.id = guid();
            }
            if ("name" in $scope.control.value.value && $scope.control.value.value.name) {
                $scope.title = $scope.control.value.value.name;
            }
            if ("dtgeContentTypeAlias" in $scope.control.value && $scope.control.value.dtgeContentTypeAlias) {
                if (!$rootScope.dtgeContentTypes[$scope.control.value.dtgeContentTypeAlias]) {

                    dtgeResources.getContentType($scope.control.value.dtgeContentTypeAlias).then(function (data2) {
                        var contentType = {
                            title: data2.title,
                            description: data2.description,
                            icon: data2.icon
                        };

                        // save to cached content types
                        $rootScope.dtgeContentTypes[$scope.control.value.dtgeContentTypeAlias] = contentType;
                        $scope.setTitleAndDescription(contentType);
                    });
                }
                else {
                    $scope.setTitleAndDescription($rootScope.dtgeContentTypes[$scope.control.value.dtgeContentTypeAlias]);
                }
            }
            if (callback)
                callback();
        };

        $scope.setTitleAndDescription = function (contentType) {
            $scope.title = contentType.title;
            $scope.description = contentType.description;
            $scope.icon = contentType.icon;
        };

        $scope.setDocType = function () {

            overlayOptions.editorName = $scope.control.editor.name;
            overlayOptions.allowedDocTypes = $scope.control.editor.config.allowedDocTypes || [];
            overlayOptions.showDocTypeSelectAsGrid = $scope.control.editor.config.showDocTypeSelectAsGrid === true;
            overlayOptions.nameTemplate = $scope.control.editor.config.nameTemplate;
            overlayOptions.size = $scope.control.editor.config.largeDialog ? null : $scope.control.editor.config.overlaySize || "small";

            overlayOptions.dialogData = {
                docTypeAlias: $scope.control.value.dtgeContentTypeAlias,
                value: $scope.control.value.value,
                id: $scope.control.value.id
            };
            overlayOptions.close = function () {
                // ensure an empty doctype is not persisted
                if($scope.control.$initializing){
                    $scope.removeControl($scope.area, $scope.control.$index -1);
                }

                editorService.close();
            }
            overlayOptions.submit = function (newModel) {

                        // Copy property values to scope model value
                        if (newModel.node) {
                            var value = {
                                name: newModel.editorName
                            };

                            for (var v = 0; v < newModel.node.variants.length; v++) {
                                var variant = newModel.node.variants[v];
                                for (var t = 0; t < variant.tabs.length; t++) {
                                    var tab = variant.tabs[t];
                                    for (var p = 0; p < tab.properties.length; p++) {
                                        var prop = tab.properties[p];
                                        if (typeof prop.value !== "function") {
                                            value[prop.alias] = prop.value;
                                        }
                                    }
                                }
                            }

                            if (newModel.nameExp) {
                                var newName = newModel.nameExp(value); // Run it against the stored dictionary value, NOT the node object
                                if (newName && (newName = $.trim(newName))) {
                                    value.name = newName;
                                }
                            }

                            newModel.dialogData.value = value;
                        } else {
                            newModel.dialogData.value = null;

                        }

                        $scope.setValue({
                            dtgeContentTypeAlias: newModel.dialogData.docTypeAlias,
                            value: newModel.dialogData.value,
                            id: newModel.dialogData.id
                        });
                        $scope.setPreview($scope.control.value);
                        editorService.close();
            };

            editorService.open(overlayOptions);
        };

        $scope.setPreview = function (model) {
            if ($scope.control.editor.config && "enablePreview" in $scope.control.editor.config && $scope.control.editor.config.enablePreview) {
                dtgeResources.getEditorMarkupForDocTypePartial(editorState.current.id, model.id,
                    $scope.control.editor.alias, model.dtgeContentTypeAlias, model.value,
                    $scope.control.editor.config.viewPath,
                    $scope.control.editor.config.previewViewPath,
                    !!editorState.current.publishDate)
                    .then(function (response) {
                        var htmlResult = response.data;
                        if (htmlResult.trim().length > 0) {
                            $scope.preview = htmlResult;
                        }
                    });
            }
        };

        function init() {
            $timeout(function () {
                if ($scope.control.$initializing) {
                    $scope.setDocType();
                } else if ($scope.control.value) {
                    $scope.setPreview($scope.control.value);
                }
            }, 200);
        }

        if ($scope.control.value) {
            if (!$scope.control.value.dtgeContentTypeAlias && $scope.control.value.docType) {
                $scope.control.value.dtgeContentTypeAlias = $scope.control.value.docType;
            }
            if ($scope.control.value.docType) {
                delete $scope.control.value.docType;
            }
            if (isGuid($scope.control.value.dtgeContentTypeAlias)) {
                dtgeResources.getContentTypeAliasByGuid($scope.control.value.dtgeContentTypeAlias).then(function (data1) {
                    $scope.control.value.dtgeContentTypeAlias = data1.alias;
                    $scope.setValue($scope.control.value, init);
                });
            } else {
                $scope.setValue($scope.control.value, init);
            }
        } else {
            $scope.setValue({
                id: guid(),
                dtgeContentTypeAlias: "",
                value: {}
            }, init);
        }

        // Load preview css / js files
        if ($scope.control.editor.config && "enablePreview" in $scope.control.editor.config && $scope.control.editor.config.enablePreview) {
            if ("previewCssFilePath" in $scope.control.editor.config && $scope.control.editor.config.previewCssFilePath) {
                assetsService.loadCss($scope.control.editor.config.previewCssFilePath, $scope);
            };

            if ("previewJsFilePath" in $scope.control.editor.config && $scope.control.editor.config.previewJsFilePath) {
                assetsService.loadJs($scope.control.editor.config.previewJsFilePath, $scope);
            }
        }

        function guid() {
            function s4() {
                return Math.floor((1 + Math.random()) * 0x10000)
                    .toString(16)
                    .substring(1);
            }
            return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
                s4() + '-' + s4() + s4() + s4();
        }

        function isGuid(input) {
            return new RegExp("^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$", "i").test(input.toString());
        }

    }
]);

angular.module("umbraco").controller("Our.Umbraco.DocTypeGridEditor.Dialogs.DocTypeGridEditorDialog",
    [
        "$scope",
        "$interpolate",
        "formHelper",
        "contentResource",
        "Our.Umbraco.DocTypeGridEditor.Resources.DocTypeGridEditorResources",
        "Our.Umbraco.DocTypeGridEditor.Services.DocTypeGridEditorUtilityService",
        "blueprintConfig",
        "contentEditingHelper",
        "serverValidationManager",

        function ($scope, $interpolate, formHelper, contentResource, dtgeResources, dtgeUtilityService, blueprintConfig, contentEditingHelper, serverValidationManager) {

            var vm = this;
            vm.submit = submit;
            vm.close = close;
            vm.loading = true;
            vm.blueprintConfig = blueprintConfig;

            function cleanup() {
                if ($scope.model.node.id > 0){
                    // delete any temporary blueprints used for validation
                    contentResource.deleteBlueprint($scope.model.node.id);
                }

                //clear server validation messages when this editor is destroyed
                serverValidationManager.clear();
            }

            $scope.$on('$destroy', cleanup);

            function submit() {
                if ($scope.model.submit) {
                    $scope.model.node.name = "Dtge Temp: " + $scope.model.node.key;
                    $scope.model.node.variants[0].name = $scope.model.node.name
                    $scope.model.node.variants[0].save = true;

                    // save the content as a blueprint, to trigger validation
                    var args = {
                        saveMethod: contentResource.saveBlueprint,
                        scope: $scope,
                        content: $scope.model.node,
                        create: true,
                        action: "save",
                        showNotifications: true,
                        softRedirect: true
                    }

                    contentEditingHelper.contentEditorPerformSave(args).then(function (data) {
                            $scope.model.submit($scope.model);
                        },
                        function (err) {

                        });
                }
            }
            function close() {
                if ($scope.model.close) {
                    $scope.model.close();
                }
            }

            $scope.docTypes = [];
            $scope.dialogMode = null;
            $scope.selectedDocType = null;
            $scope.model.node = null;

            var nameExp = !!$scope.model.nameTemplate
                ? $interpolate($scope.model.nameTemplate)
                : undefined;

            $scope.model.nameExp = nameExp;

            function createBlank() {
                $scope.dialogMode = "edit";
                loadNode();
            };

            function createOrSelectBlueprintIfAny(docType) {

                $scope.model.dialogData.docTypeAlias = docType.alias;
                var blueprintIds = _.keys(docType.blueprints || {});
                $scope.selectedDocType = docType;

                if (blueprintIds.length) {
                    if (blueprintConfig.skipSelect) {
                        createFromBlueprint(blueprintIds[0]);
                    } else {
                        $scope.dialogMode = "selectBlueprint";
                    }
                } else {
                    createBlank();
                }
            };

            function createFromBlueprint(blueprintId) {
                contentResource.getBlueprintScaffold(-1, blueprintId).then(function (data) {
                    // Assign the model to scope
                    $scope.nodeContext = $scope.model.node = data;
                    $scope.dialogMode = "edit";
                    vm.content = $scope.nodeContext.variants[0];
                    vm.loading = false;
                });
            };

            $scope.createBlank = createBlank;
            $scope.createOrSelectBlueprintIfAny = createOrSelectBlueprintIfAny;
            $scope.createFromBlueprint = createFromBlueprint;

            function loadNode() {
                vm.loading = true;
                contentResource.getScaffold(-1, $scope.model.dialogData.docTypeAlias).then(function (data) {

                    // Merge current value
                    if ($scope.model.dialogData.value) {
                        for (var v = 0; v < data.variants.length; v++) {
                            var variant = data.variants[v];
                            for (var t = 0; t < variant.tabs.length; t++) {
                                var tab = variant.tabs[t];
                                for (var p = 0; p < tab.properties.length; p++) {
                                    var prop = tab.properties[p];
                                    if ($scope.model.dialogData.value[prop.alias]) {
                                        prop.value = $scope.model.dialogData.value[prop.alias];
                                    }
                                }
                            }
                        }
                    };

                    // Assign the model to scope
                    $scope.nodeContext = $scope.model.node = data;
                    vm.content = $scope.nodeContext.variants[0];
                    vm.loading = false;
                });
            }

            if ($scope.model.dialogData.docTypeAlias) {
                $scope.dialogMode = "edit";
                loadNode();
            } else {
                $scope.dialogMode = "selectDocType";
                // No data type, so load a list to choose from
                dtgeResources.getContentTypes($scope.model.allowedDocTypes).then(function (docTypes) {
                    $scope.docTypes = docTypes;
                    if ($scope.docTypes.length == 1) {
                        createOrSelectBlueprintIfAny($scope.docTypes[0]);
                    }
                    else {
                        vm.loading = false;
                    }
                });
            }

        }

    ]);
<|endoftext|>