<commit_before>//Main JS file
var gQuery = require('libs/gquery/dist/gquery.min.js'),
    TweenLite = require('libs/TweenLite.js'),
    TimelineLite = require('libs/TimelineLite.js'),
    CSSPlugin = require('libs/CSSPlugin.js'),
    UTIL = require('./util.js');
// You can use $('.class').selector or $('#id').selector for
// jQuery-like workflow. $.each(selector, callback), $.css({Object}),
// $.on(eventType, callback). Greensock TweenLite and TimelineLite
// are also included.
//
//
// Generate a CTA button:
//
// UTIL.cta($(selector), {
//     style: String (required),
//     w: Number (required),
//     h: Number (required),
//     posX: Number (only necessary for full),
//     posY: Number (only necessary for full),
//     color: String (required),
//     rollover: String,
//     textW: Number (required),
//     textH: Number (required),
//     animate: Boolean (required),
//     delay: Number (required)
// });
//
// Style:  full (full polygon, usually 300x600's),
//         right (half polygon from right side, usually 728x90's),
//         left (half polygon from left side, usually 300x250's),
//         none (no polygon from bottom, usually 160x600's)
// Color: Hex value
// Rollover: If you would like to control the color of the cta during rollover, enter here (for 'full' and 'none' cta types)
// Text: Make sure to include an svg named "cta-txt.svg", and enter in the
//       width and height values
// Delay: The time (in seconds) that you want cta to animate in

var Animations = (function () {
    'use strict';

    var timeline,
        elements = {};

    // Construct
    function Animations () {}

    // This creates all of our animation elements
    Animations.prototype.assign = function () {
        elements.ad                     = $('.ad').selector;
        elements.frame1                 = $('#scene-1').selector;
        elements.frame2                 = $('#scene-2').selector;
        elements.frame3                 = $('#scene-3').selector;
        elements.endframe               = $('#endframe').selector;
        elements.first                  = $('#element-1').selector;
        elements.second                 = $('#element-2').selector;
        elements.third                  = $('#element-3').selector;
        elements.fourth                 = $('#element-4').selector;
        elements.cta                    = $('#cta').selector;
        elements.logo                   = $('#logo').selector;
        elements.ctaBorder              = $('#cta-border').selector;
        elements.ctaContainer           = $('#cta-container').selector;
        elements.ctaPolygon             = $('#cta-polygon').selector;
        elements.ctaTxt                 = $('#cta-txt').selector;

        this.construct();
    };

    // This creates all of our animation elements
    Animations.prototype.construct = function () {
        var durationZoomIn      = 1,
            durationZoomOut     = 1,
            durationFadeIn      = 1,
            durationFadeOut     = 1,
            durationMove        = 0.5,
            durationSwipe       = 0.6,
            durationPan         = 4,
            pauseDuration       = 2;

        // create a home for our animations
        // example: timeline complete parameters:
        // timeline = new TimelineLite( {onComplete:this.onFinish, onCompleteParams:["test1", "test2"], onCompleteScope:this } );
        timeline = new TimelineLite();

        var main = new TimelineLite();
        // Frame # 1 -------------------------------------------------------------------------
        // main animation goes here, cuz
        main.to(elements.frame1, durationFadeIn, {autoAlpha: 1}, 0.5)

        // Create timeline
        timeline.add(main);

        // wait before starting the animation!
        timeline.pause();
    };

    // This Kicks off the animation on screen
    Animations.prototype.onFinish = function (scope) {
        if (!UTIL.environment.isMobile()) {
            // Desktop-specific events
        } else {
            // Mobile Specific Events
        }
    };

    Animations.prototype.begin = function () {
        // hide loader!
        // remove loading class from #content
        UTIL.removeClass(elements.ad , 'loading');
        timeline.play();
    };

    return Animations;
})();

window.onload = function () {
    var anim = new Animations();

    UTIL.cta($('#element-1'), {
        w: 160,
        h: 21,
        posX: 0,
        posY: 10,
        style: 'full',
        color: '#005096',
        textW: 90,
        textH: 7,
        animate: true,
        delay: 3
    });

    anim.assign();
    anim.begin();

    //UNCOMMENT IF ADBUILDER
    // //Ad Buider
    // var dealerTag = window.dealerName;
    // if (dealerTag.length > 20 && dealerTag.length <= 35) {
    //     $('#dealer-name').css({
    //         'font-size': '1.6em',
    //         'width': '50%',
    //         'line-height': '1.1em',
    //         'margin-top': '-1em'
    //     });
    // } else if (dealerTag.length > 35){
    //     $('#dealer-name').css({
    //         'font-size': '1.1em',
    //         'line-height': '1.2em',
    //         'margin-top': '-0.5em',
    //         'width': '50%'
    //     });
    // }
    // //set the text
    // $('#dealer-name').selector.innerHTML = dealerTag;
};
<commit_msg>add onFinish event<commit_after>//Main JS file
var gQuery = require('libs/gquery/dist/gquery.min.js'),
    TweenLite = require('libs/TweenLite.js'),
    TimelineLite = require('libs/TimelineLite.js'),
    CSSPlugin = require('libs/CSSPlugin.js'),
    UTIL = require('./util.js');
// You can use $('.class').selector or $('#id').selector for
// jQuery-like workflow. $.each(selector, callback), $.css({Object}),
// $.on(eventType, callback). Greensock TweenLite and TimelineLite
// are also included.
//
//
// Generate a CTA button:
//
// UTIL.cta($(selector), {
//     style: String (required),
//     w: Number (required),
//     h: Number (required),
//     posX: Number (only necessary for full),
//     posY: Number (only necessary for full),
//     color: String (required),
//     rollover: String,
//     textW: Number (required),
//     textH: Number (required),
//     animate: Boolean (required),
//     delay: Number (required)
// });
//
// Style:  full (full polygon, usually 300x600's),
//         right (half polygon from right side, usually 728x90's),
//         left (half polygon from left side, usually 300x250's),
//         none (no polygon from bottom, usually 160x600's)
// Color: Hex value
// Rollover: If you would like to control the color of the cta during rollover, enter here (for 'full' and 'none' cta types)
// Text: Make sure to include an svg named "cta-txt.svg", and enter in the
//       width and height values
// Delay: The time (in seconds) that you want cta to animate in

var Animations = (function () {
    'use strict';

    var timeline,
        elements = {};

    // Construct
    function Animations () {}

    // This creates all of our animation elements
    Animations.prototype.assign = function () {
        elements.ad                     = $('.ad').selector;
        elements.frame1                 = $('#scene-1').selector;
        elements.frame2                 = $('#scene-2').selector;
        elements.frame3                 = $('#scene-3').selector;
        elements.endframe               = $('#endframe').selector;
        elements.first                  = $('#element-1').selector;
        elements.second                 = $('#element-2').selector;
        elements.third                  = $('#element-3').selector;
        elements.fourth                 = $('#element-4').selector;
        elements.cta                    = $('#cta').selector;
        elements.logo                   = $('#logo').selector;
        elements.ctaBorder              = $('#cta-border').selector;
        elements.ctaContainer           = $('#cta-container').selector;
        elements.ctaPolygon             = $('#cta-polygon').selector;
        elements.ctaTxt                 = $('#cta-txt').selector;

        this.construct();
    };

    // This creates all of our animation elements
    Animations.prototype.construct = function () {
        var durationZoomIn      = 1,
            durationZoomOut     = 1,
            durationFadeIn      = 1,
            durationFadeOut     = 1,
            durationMove        = 0.5,
            durationSwipe       = 0.6,
            durationPan         = 4,
            pauseDuration       = 2;

        // create a home for our animations
        // example: timeline complete parameters:
        // timeline = new TimelineLite( {onComplete:this.onFinish, onCompleteParams:["test1", "test2"], onCompleteScope:this } );
        timeline = new TimelineLite({onComplete:this.onFinish, onCompleteScope:this});

        var main = new TimelineLite();
        // Frame # 1 -------------------------------------------------------------------------
        // main animation goes here, cuz
        main.to(elements.frame1, durationFadeIn, {autoAlpha: 1}, 0.5)

        // Create timeline
        timeline.add(main);

        // wait before starting the animation!
        timeline.pause();
    };

    // This Kicks off the animation on screen
    Animations.prototype.onFinish = function (scope) {
        if (!UTIL.environment.isMobile()) {
            // Desktop-specific events
        } else {
            // Mobile Specific Events
        }
    };

    Animations.prototype.begin = function () {
        // hide loader!
        // remove loading class from #content
        UTIL.removeClass(elements.ad , 'loading');
        timeline.play();
    };

    return Animations;
})();

window.onload = function () {
    var anim = new Animations();

    UTIL.cta($('#element-1'), {
        w: 160,
        h: 21,
        posX: 0,
        posY: 10,
        style: 'full',
        color: '#005096',
        textW: 90,
        textH: 7,
        animate: true,
        delay: 3
    });

    anim.assign();
    anim.begin();

    //UNCOMMENT IF ADBUILDER
    // //Ad Buider
    // var dealerTag = window.dealerName;
    // if (dealerTag.length > 20 && dealerTag.length <= 35) {
    //     $('#dealer-name').css({
    //         'font-size': '1.6em',
    //         'width': '50%',
    //         'line-height': '1.1em',
    //         'margin-top': '-1em'
    //     });
    // } else if (dealerTag.length > 35){
    //     $('#dealer-name').css({
    //         'font-size': '1.1em',
    //         'line-height': '1.2em',
    //         'margin-top': '-0.5em',
    //         'width': '50%'
    //     });
    // }
    // //set the text
    // $('#dealer-name').selector.innerHTML = dealerTag;
};
<|endoftext|>


<commit_before>var React = require("react")
var {div, span, label} = React.DOM
var cx = require("classnames")

module.exports = {
  errorList(errors) {
    let i = 0
    return (errors || []).map( (msg) => module.exports.error(msg, i++))
  },

  error(msg, i=0) {
    return span({className: "help-block", key: `error-${i}`},
      React.DOM.i({className: "fa fa-exclamation-circle"}, ` ${msg}`),
    )
  },

  label(props, overrides = {}) {
    if (!props.label) return ""
    let labelHtml = Object.assign({}, props, overrides)
    labelHtml.className = cx(labelHtml.className, {
      "col-sm-3": props.layout === "horizontal",
    })
    return div({},
      label(labelHtml, props.label),
      savedText({saved: props.saved && props.layout === "vertical"}),
    )
  },

  savedText({saved}) {
    return saved ? span({className: "frigb-saved pull-right"}, "saved") : ""
  },

  savedNotification(props) {
    let {layout, label, saved} = this.props
    let savedInline = span({className: "frigb-saved-inline"}, "saved")

    if (label === false && saved) return savedInline
    if (label && saved && layout == "horizontal") return savedInline
  },

  inputContainerCx(props) {
    return cx({"col-sm-9": props.layout == "horizontal"})
  },

  sizeClassNames(props) {
    var classes = {}
    var sizes = ["xs", "sm", "md", "lg"]
    // Adding column classes
    for (var k of sizes) {
      if (props[k] != null) classes[`col-${k}-${props[k]}`] = true
    }
    // Adding offset classes
    for (var size of sizes) {
      k = `${size}Offset`
      if (props[k] == null) continue
      classes[`col-${size}-offset-${props[k]}`] = true
    }
    return classes
  },

  formGroupCx(props, overrides = {}) {
    let isCheckbox = props.inputHtml.type === "checkbox"
    return cx(Object.assign({
      "form-group": !isCheckbox,
      "checkbox": isCheckbox,
      "has-error": props.errors != null,
      "has-success": props.modified && props.errors == null,
    }, overrides))
  },

}

var {savedText} = module.exports
<commit_msg>fixing savedNotification method<commit_after>var React = require("react")
var {div, span, label} = React.DOM
var cx = require("classnames")

module.exports = {
  errorList(errors) {
    let i = 0
    return (errors || []).map( (msg) => module.exports.error(msg, i++))
  },

  error(msg, i=0) {
    return span({className: "help-block", key: `error-${i}`},
      React.DOM.i({className: "fa fa-exclamation-circle"}, ` ${msg}`),
    )
  },

  label(props, overrides = {}) {
    if (!props.label) return ""
    let labelHtml = Object.assign({}, props, overrides)
    labelHtml.className = cx(labelHtml.className, {
      "col-sm-3": props.layout === "horizontal",
    })
    return div({},
      label(labelHtml, props.label),
      savedText({saved: props.saved && props.layout === "vertical"}),
    )
  },

  savedText({saved}) {
    return saved ? span({className: "frigb-saved pull-right"}, "saved") : ""
  },

  savedNotification(props) {
    let {layout, label, saved} = props
    let savedInline = span({className: "frigb-saved-inline"}, "saved")

    if (label === false && saved) return savedInline
    if (label && saved && layout == "horizontal") return savedInline
  },

  inputContainerCx(props) {
    return cx({"col-sm-9": props.layout == "horizontal"})
  },

  sizeClassNames(props) {
    var classes = {}
    var sizes = ["xs", "sm", "md", "lg"]
    // Adding column classes
    for (var k of sizes) {
      if (props[k] != null) classes[`col-${k}-${props[k]}`] = true
    }
    // Adding offset classes
    for (var size of sizes) {
      k = `${size}Offset`
      if (props[k] == null) continue
      classes[`col-${size}-offset-${props[k]}`] = true
    }
    return classes
  },

  formGroupCx(props, overrides = {}) {
    let isCheckbox = props.inputHtml.type === "checkbox"
    return cx(Object.assign({
      "form-group": !isCheckbox,
      "checkbox": isCheckbox,
      "has-error": props.errors != null,
      "has-success": props.modified && props.errors == null,
    }, overrides))
  },

}

var {savedText} = module.exports
<|endoftext|>


<commit_before>(function($) {

  function dirname(path) {
    return path.indexOf('/') >= 0 ? path.replace( /\\/g, '/' ).replace( /\/[^\/]*$/, '' ) : ".";
  }

  function isAbsolutePath(path) {
    return (new RegExp('^([a-z]+://|//)')).test(path);
  }

  function getXMLStylesheet(url, doc) {
    var i, child, children = doc.childNodes, match, file = null;
    for (i = 0; i < children.length; i++) {
      child = children[i];
      if (child.target === 'xml-stylesheet') {
        match = child.data.match(/href=\"(.*)\"/);
        if (match) {
          file = match[1];
          // Check for relative path
          if (!isAbsolutePath(file)) {
            // Concat paths
            file = dirname(url) + "/" + file;
          }
          break;
        }
      }
    }
    return file;
  }

  function transformToDocument(xml, xsl, options) {
    options = options || {};
    var result = null, xsltProcessor;
    // Transform
    if (xml.implementation && xml.implementation.createDocument) {
      // W3C
      xsltProcessor = new XSLTProcessor();
      try {
        xsltProcessor.importStylesheet(xsl);
      } catch (e) {
        console.error(e);
      }
      result = xsltProcessor.transformToDocument(xml);
    } else {
      // Internet Explorer
      var impl = new ActiveXObject("Microsoft.XMLDOM");
      if (impl) {
        var xslt = new ActiveXObject("MSXML2.FreeThreadedDOMDocument");
        var processor   = new ActiveXObject("Msxml2.XSLTemplate");
        processor.stylesheet = xsl;
        var objXSLTProc = processor.createProcessor();
        objXSLTProc.input = xml;
        objXSLTProc.transform();
        result = objXSLTProc.output;
      }
    }

    function unescapeOutput(result) {
      $(result).find('*').contents().filter(function () { return this.nodeType === 3; }).each(function() {
        var frag = document.createDocumentFragment();
        var holder = document.createElement("div");
        holder.innerHTML = this.nodeValue;
        $(holder).contents().each(function() {
          frag.appendChild(this);
        });
        $(frag).insertBefore(this);
        $(this).remove();
      });
    }

    return result;
  }

  $.ajaxTransport("xslt", function(options, originalOptions, jqXHR, headers, completeCallback   ) {
    if (options.dataType === 'xslt' || options.xmlStylesheet) {
      options.dataType = 'xslt';
      var xhr, aborted = false;
      return {
        send: function( headers, completeCallback ) {
          // Load Document
          xhr = $.ajax($.extend(true, {}, options, {
            dataType: 'xml',
            success: function(xml) {
              if (xml && !aborted) {
                var xmlStylesheet = options.xmlStylesheet || getXMLStylesheet(options.url, xml);
                if (xmlStylesheet) {
                  // Load Stylesheet
                  xhr = $.ajax({
                    url: xmlStylesheet,
                    dataType: 'xml',
                    success: function(xmlStylesheet) {
                      if (!aborted) {
                        // Transform
                        var result = transformToDocument(xml, xmlStylesheet, options);
                        if (result) {
                          if (options.unescapeOutput) {
                            unescapeOutput(result);
                          }
                          // Success
                          completeCallback(200, "Transform successful", {xslt: result});
                        } else {
                          // Fail
                          completeCallback(400, "Error transforming xml", {});
                        }
                      }
                    },
                    error: function() {
                      if (!aborted) {
                        completeCallback(xhr.status, xhr.statusText, {});
                      }
                    }
                  });
                } else {
                  // No Stylesheet provided
                  completeCallback(400, "No Stylesheet provided", {});
                }
              }
            },
            error: function(doc) {
              if (!aborted) {
                completeCallback(xhr.status, xhr.statusCode, {});
              }
            }
          }));
        },
        abort: function() {
          aborted = true;
          if (xhr) {
            xhr.abort();
          }
        }
      };
    }
  });

})(jQuery);<commit_msg>Fixed IE<commit_after>(function($) {

  function dirname(path) {
    return path.indexOf('/') >= 0 ? path.replace( /\\/g, '/' ).replace( /\/[^\/]*$/, '' ) : ".";
  }

  function isAbsolutePath(path) {
    return (new RegExp('^([a-z]+://|//)')).test(path);
  }

  function getXMLStylesheet(url, doc) {
    var i, child, children = doc.childNodes, match, file = null;
    for (i = 0; i < children.length; i++) {
      child = children[i];
      if (child.target === 'xml-stylesheet') {
        match = child.data.match(/href=\"([^'"]*)\"/);
        if (match) {
          file = match[1];
          // Check for relative path
          if (!isAbsolutePath(file)) {
            // Concat paths
            file = dirname(url) + "/" + file;
          }
          break;
        }
      }
    }
    return file;
  }

  function serializeToString(xml) {
    if (window.XMLSerializer) {
      // W3C
      var serializer = new XMLSerializer();
      var string = serializer.serializeToString(xml);
      return string;
    } else if (typeof xml.xml === 'object') {
      // Internet Explorer 8
      return xml.xml;
    }
  }

  // Based on https://gist.github.com/1129031 by Eli Grey, http://eligrey.com
  function parseFromString(xmlString, outputType) {
    var
      doc;

    // Firefox/Opera/IE throw errors on unsupported types
    try {
      doc = (new DOMParser()).parseFromString(xmlString, outputType);
      if (doc) {
        // Output type is natively supported
        return doc;
      }
    } catch (ex) {
    }

    // HTML-Extension
    if (/^\s*text\/html\s*(?:;|$)/i.test(outputType)) {
      doc = document.implementation.createHTMLDocument("");
      if (markup.toLowerCase().indexOf('<!doctype') > -1) {
        doc.documentElement.innerHTML = markup;
      }
      else {
        doc.body.innerHTML = markup;
      }
      return doc;
    }

    // Unsupported output type
    return null;
  }

  function transformToDocument(xml, xsl, options) {

    options = options || {};
    var result = null, xsltProcessor;

    if ('XSLTProcessor' in window && xml.implementation && xml.implementation.createDocument) {

      // W3C
      xsltProcessor = new XSLTProcessor();
      try {
        xsltProcessor.importStylesheet(xsl);
      } catch (e) {
        console.error(e);
      }
      result = xsltProcessor.transformToDocument(xml);

    } else if ('DOMParser' in window && (window.ActiveXObject || "ActiveXObject" in window)) {

      // Internet Explorer 9+
      try {

        var
          // Resolve output type
          outputElement = xsl.getElementsByTagNameNS('http://www.w3.org/1999/XSL/Transform', 'output')[0],
          outputMethod = outputElement && outputElement.getAttribute('method') || 'xml',
          outputType = outputMethod === 'html' ? 'text/html' : 'text/xml',

          // Serialize string
          xmlString = serializeToString(xml);

        // Replace entities
        // TODO: Configurable as option
        xmlString = xmlString.replace(/\/gi, '');

        var xmlDoc = new ActiveXObject("Msxml2.DOMDocument");
        xmlDoc.async = false;
        xmlDoc.resolveExternals = false;
        xmlDoc.validateOnParse = false;
        xmlDoc.loadXML(xmlString);

        var
          xslDoc = new ActiveXObject("Msxml2.FreeThreadedDOMDocument"),
          xslString = serializeToString(xsl);

        xslDoc.loadXML(xslString);

        var output;
        if ('transformNode' in xmlDoc) {
          output = xmlDoc.transformNode(xslDoc);
        }

        if (!output) {
          var xslt = new ActiveXObject("Msxml2.XSLTemplate");
          xslt.stylesheet = xslDoc;
          xsltProcessor = xslt.createProcessor();
          xsltProcessor.input = xmlDoc;
          xsltProcessor.transform();
          output = xsltProcessor.output;
        }

        result = parseFromString( output , outputType );

      } catch (e) {
        console.error(e);
      }
    } else {
      // Unsupported
      console.warn("XSLT is not supported");
    }
    return result;
  }

  function unescapeOutput(result) {
    $(result).find('*').contents().filter(function () { return this.nodeType === 3; }).each(function() {
      var frag = document.createDocumentFragment();
      var holder = document.createElement("div");
      holder.innerHTML = this.nodeValue;
      $(holder).contents().each(function() {
        frag.appendChild(this);
      });
      $(frag).insertBefore(this);
      $(this).remove();
    });
  }

  $.ajaxTransport("xslt", function(options, originalOptions, jqXHR, headers, completeCallback   ) {

    if (options.dataType === 'xslt' || options.xmlStylesheet) {
      options.dataType = 'xslt';
      var xhr, aborted = false;
      return {
        send: function( headers, completeCallback ) {
          // Load Document
          xhr = $.ajax($.extend(true, {}, options, {
            dataType: 'xml',
            contentType: 'application/xml',
            success: function(xml) {
              if (xml && !aborted) {
                var xmlStylesheet = options.xmlStylesheet || getXMLStylesheet(options.url, xml);
                if (xmlStylesheet) {
                  // Load Stylesheet
                  xhr = $.ajax({
                    url: xmlStylesheet,
                    dataType: 'xml',
                    contentType: 'text/xml',
                    success: function(xmlStylesheet) {
                      if (!aborted) {
                        // Transform
                        var result = transformToDocument(xml, xmlStylesheet, options);
                        if (result) {
                          if (options.unescapeOutput) {
                            unescapeOutput(result);
                          }
                          // Success
                          completeCallback(200, "Transform successful", {xslt: result});
                        } else {
                          // Fail
                          completeCallback(400, "Error transforming xml", {});
                        }
                      }
                    },
                    error: function() {
                      if (!aborted) {
                        completeCallback(xhr.status, xhr.statusText, {});
                      }
                    }
                  });
                } else {
                  // No Stylesheet provided
                  completeCallback(400, "No Stylesheet provided", {});
                }
              }
            },
            error: function(doc) {
              if (!aborted) {
                completeCallback(xhr.status, xhr.statusCode, {});
              }
            }
          }));
        },
        abort: function() {
          aborted = true;
          if (xhr) {
            xhr.abort();
          }
        }
      };
    }
  });

})(jQuery);<|endoftext|>


<commit_before><commit_msg>added table headers<commit_after><|endoftext|>


<commit_before>var i18nContext = require('i18n-context')('ember_file_uploader', require.resolve('../locales')),
    t = i18nContext.t,
    tProperty = i18nContext.tProperty,
    QueueItem = require('./queue-item'),
    manager = require('./manager'),
    config = require('./config');

module.exports = Ember.Component.extend({
    template: require('../templates/file-uploader'),

    classNameBindings: [':file-uploader'],

    queue: null,
    multiple: true,

    url: '/files',

    allowDrag: true,
    dragTip: tProperty('dragTip', t('or_drag_and_drop')),
    dropTip: tProperty('dropTip', t('drop_files_here')),
    dropSelector: null,

    inputSelector: null,

    accept: null,

    buttonText: tProperty('buttonText', function() {
        return this.get('multiple') ? t('select_files') : t('select_file');
    }).property('multiple'),
    buttonStyle: null,
    buttonSize: 'small',

    batch: null,

    thumbnailNames: '',

    setupQueue: function() {
        this.set('queue', []);
    }.on('init'),

    didInsertElement: function() {
        this.setupFileInput();
        if (this.get('allowDrag')) {
            this.setupDropTarget();
        }
    },

    stopEvent: function(e) {
        e.stopPropagation();
        e.preventDefault();
    },
    findBySelector: function(selector, what) {
        var el = this.$().closest(selector);
        if (el.length) {
            return el;
        }
        el = $(selector);
        if (el.length) {
            return el;
        }
        throw new Error('No file-uploader '+what+' was found by the selector '+selector);
    },

    setupFileInput: function() {
        var self = this,
            selector = this.get('inputSelector'),
            parent,
            input,
            accept = Em.Handlebars.Utils.escapeExpression(this.get('accept'));
        if (selector) {
            parent = this.findBySelector(selector, 'input parent');
            parent.addClass('file-uploader-input-parent');
        } else {
            parent = this.$('.file-uploader-input-parent');
        }
        parent.append('<input type="file" class="file-uploader-input" accept="'+accept+'"' + (this.get('multiple') ? ' multiple' : '') + '/>');
        input = parent.find('> .file-uploader-input');
        if (selector) {
            this.set('externalInput', input);
        }
        input.change(function(e) {
            Em.run(function() {
                self.enqueue(input[0].files);
                input[0].value = null;
            });
        });
        //Add .hover class to the upload button, since it's masked by the invisible file input field
        parent.mouseenter(function() {
            parent.find('.button').addClass('hover');
        });
        parent.mouseleave(function() {
            parent.find('.button').removeClass('hover');
        });
    },

    getDropTarget: function() {
        var selector = this.get('dropSelector');
        if (selector) {
            return this.findBySelector(selector, 'drop target');
        } else {
            return this.$();
        }
    },
    getDropOverlay: function() {
        var overlay = this.get('dropOverlay');
        if (!overlay) {
            var dropTarget = this.getDropTarget();
            dropTarget.append(
                '
'+
                '
'+
                '
'+this.get('dropTip')+'
'+
                '
'+t('escape_tip')+'
'+
                '
'+
                '
'
            );
            overlay = dropTarget.find(' > .file-uploader-overlay');
            this.set('dropOverlay', overlay);
        }
        return overlay;
    },

    setupDropTarget: function() {
        this.addOrRemoveDropTargetEvents('on');
    },

    addOrRemoveDropTargetEvents: function(method) {
        var dropTarget = this.getDropTarget(),
            body = $(this.container.lookup('application:main').get('rootElement'));
        body[method]('dragenter', Billy.proxy(this.onBodyDragEnter, this));
        body[method]('dragleave', Billy.proxy(this.onBodyDragLeave, this));
        body[method]('dragover', Billy.proxy(this.onBodyDragOver, this));
        body[method]('drop', Billy.proxy(this.onBodyDrop, this));
        dropTarget[method]('dragover', Billy.proxy(this.onDragOver, this));
        dropTarget[method]('dragleave', Billy.proxy(this.onDragLeave, this));
        dropTarget[method]('drop', Billy.proxy(this.onDrop, this));
    },

    onBodyDragEnter: function(e) {
        this.ignoreNextBodyDragLeave = true;
        this.showDropOverlay();
        return false;
    },
    onBodyDragLeave: function(e) {
        if (this.ignoreNextBodyDragLeave) {
            this.ignoreNextBodyDragLeave = false;
        } else {
            this.hideDropOverlay();
        }
    },
    onBodyDragOver: function(e) {
        this.stopEvent(e);
        return false;
    },
    onBodyDrop: function(e) {
        this.hideDropOverlay();
        this.stopEvent(e);
    },
    onDragOver: function(e) {
        this.getDropOverlay().addClass('hover');
    },
    onDragLeave: function(e) {
        this.getDropOverlay().removeClass('hover');
    },
    onDrop: function(e) {
        var self = this;
        Em.run(function() {
            var files = e.dataTransfer.files;
            self.enqueue(files);
        });
    },
    showDropOverlay: function() {
        var dropTarget = this.getDropTarget(),
            overlay = this.getDropOverlay();
        dropTarget.addClass('has-overlay');
        overlay.css('display', 'block');
        overlay.height(dropTarget.outerHeight());
        overlay.width(dropTarget.outerWidth());
        overlay.position({
            my: 'top left',
            at: 'top left',
            of: dropTarget
        });
    },
    hideDropOverlay: function() {
        var dropTarget = this.getDropTarget(),
            overlay = this.getDropOverlay();
        dropTarget.removeClass('has-overlay');
        overlay.css('display', 'none');
    },

    willDestroyElement: function() {
        var overlay = this.get('dropOverlay'),
            externalInput = this.get('externalInput');
        //Overlay
        if (overlay) {
            overlay.remove();
        }
        //External input
        if (externalInput) {
            externalInput.parent().removeClass('file-uploader-input-parent');
            externalInput.remove();
        }
        //Drop target
        if (this.get('allowDrag')) {
            this.addOrRemoveDropTargetEvents('off');
        }
    },

    enqueue: function(file) {
        var self = this,
            item,
            batch = this.get('batch');
        if (Em.isArray(file)) {
            Array.prototype.forEach.call(file, function(f) {
                this.enqueue(f);
            }, this);
            return;
        }
        if (!this.get('multiple') && this.get('queue.length') > 0) {
            return;
        }
        item = QueueItem.create({
            fileUploader: this,
            file: file
        });
        item.on('upload', function(file, payload) {
            BD.store.sideload(payload);
            self.sendAction('didUploadFile', {
                file: file,
                payload: payload
            });
        });
        item.on('done', function(item) {
            if (self.get('isDestroyed')) {
                return;
            }
            self.get('queue').removeObject(item);
        });
        this.get('queue').pushObject(item);
        if (batch) {
            batch.pushObject(item);
        }
        manager.enqueue(item);
    },

    uploadButtonIsVisible: function() {
        return (!this.get('inputSelector') && (this.get('multiple') || this.get('queue.length') === 0));
    }.property('inputSelector', 'multiple', 'queue.@each'),

    queueItemViewClass: require('./queue-item-view')
});

module.exports.Batch = require('./batch');

module.exports.locale = i18nContext.locale;

module.exports.lang = function() {
    console.warn('.lang() is deprecated. Use .locale() instead');
    return i18nContext.locale.apply(null, arguments);
};

module.exports.setHeader = function(key, value) {
    config.headers[key] = value;
};
module.exports.clearHeader = function(key) {
    delete(config.headers[key]);
};
module.exports.clearHeaders = function() {
    config.headers = {};
};
<commit_msg>Added removeQueueItem method to make it easier to override<commit_after>var i18nContext = require('i18n-context')('ember_file_uploader', require.resolve('../locales')),
    t = i18nContext.t,
    tProperty = i18nContext.tProperty,
    QueueItem = require('./queue-item'),
    manager = require('./manager'),
    config = require('./config');

module.exports = Ember.Component.extend({
    template: require('../templates/file-uploader'),

    classNameBindings: [':file-uploader'],

    queue: null,
    multiple: true,

    url: '/files',

    allowDrag: true,
    dragTip: tProperty('dragTip', t('or_drag_and_drop')),
    dropTip: tProperty('dropTip', t('drop_files_here')),
    dropSelector: null,

    inputSelector: null,

    accept: null,

    buttonText: tProperty('buttonText', function() {
        return this.get('multiple') ? t('select_files') : t('select_file');
    }).property('multiple'),
    buttonStyle: null,
    buttonSize: 'small',

    batch: null,

    thumbnailNames: '',

    setupQueue: function() {
        this.set('queue', []);
    }.on('init'),

    didInsertElement: function() {
        this.setupFileInput();
        if (this.get('allowDrag')) {
            this.setupDropTarget();
        }
    },

    stopEvent: function(e) {
        e.stopPropagation();
        e.preventDefault();
    },
    findBySelector: function(selector, what) {
        var el = this.$().closest(selector);
        if (el.length) {
            return el;
        }
        el = $(selector);
        if (el.length) {
            return el;
        }
        throw new Error('No file-uploader '+what+' was found by the selector '+selector);
    },

    setupFileInput: function() {
        var self = this,
            selector = this.get('inputSelector'),
            parent,
            input,
            accept = Em.Handlebars.Utils.escapeExpression(this.get('accept'));
        if (selector) {
            parent = this.findBySelector(selector, 'input parent');
            parent.addClass('file-uploader-input-parent');
        } else {
            parent = this.$('.file-uploader-input-parent');
        }
        parent.append('<input type="file" class="file-uploader-input" accept="'+accept+'"' + (this.get('multiple') ? ' multiple' : '') + '/>');
        input = parent.find('> .file-uploader-input');
        if (selector) {
            this.set('externalInput', input);
        }
        input.change(function(e) {
            Em.run(function() {
                self.enqueue(input[0].files);
                input[0].value = null;
            });
        });
        //Add .hover class to the upload button, since it's masked by the invisible file input field
        parent.mouseenter(function() {
            parent.find('.button').addClass('hover');
        });
        parent.mouseleave(function() {
            parent.find('.button').removeClass('hover');
        });
    },

    getDropTarget: function() {
        var selector = this.get('dropSelector');
        if (selector) {
            return this.findBySelector(selector, 'drop target');
        } else {
            return this.$();
        }
    },
    getDropOverlay: function() {
        var overlay = this.get('dropOverlay');
        if (!overlay) {
            var dropTarget = this.getDropTarget();
            dropTarget.append(
                '
'+
                '
'+
                '
'+this.get('dropTip')+'
'+
                '
'+t('escape_tip')+'
'+
                '
'+
                '
'
            );
            overlay = dropTarget.find(' > .file-uploader-overlay');
            this.set('dropOverlay', overlay);
        }
        return overlay;
    },

    setupDropTarget: function() {
        this.addOrRemoveDropTargetEvents('on');
    },

    addOrRemoveDropTargetEvents: function(method) {
        var dropTarget = this.getDropTarget(),
            body = $(this.container.lookup('application:main').get('rootElement'));
        body[method]('dragenter', Billy.proxy(this.onBodyDragEnter, this));
        body[method]('dragleave', Billy.proxy(this.onBodyDragLeave, this));
        body[method]('dragover', Billy.proxy(this.onBodyDragOver, this));
        body[method]('drop', Billy.proxy(this.onBodyDrop, this));
        dropTarget[method]('dragover', Billy.proxy(this.onDragOver, this));
        dropTarget[method]('dragleave', Billy.proxy(this.onDragLeave, this));
        dropTarget[method]('drop', Billy.proxy(this.onDrop, this));
    },

    onBodyDragEnter: function(e) {
        this.ignoreNextBodyDragLeave = true;
        this.showDropOverlay();
        return false;
    },
    onBodyDragLeave: function(e) {
        if (this.ignoreNextBodyDragLeave) {
            this.ignoreNextBodyDragLeave = false;
        } else {
            this.hideDropOverlay();
        }
    },
    onBodyDragOver: function(e) {
        this.stopEvent(e);
        return false;
    },
    onBodyDrop: function(e) {
        this.hideDropOverlay();
        this.stopEvent(e);
    },
    onDragOver: function(e) {
        this.getDropOverlay().addClass('hover');
    },
    onDragLeave: function(e) {
        this.getDropOverlay().removeClass('hover');
    },
    onDrop: function(e) {
        var self = this;
        Em.run(function() {
            var files = e.dataTransfer.files;
            self.enqueue(files);
        });
    },
    showDropOverlay: function() {
        var dropTarget = this.getDropTarget(),
            overlay = this.getDropOverlay();
        dropTarget.addClass('has-overlay');
        overlay.css('display', 'block');
        overlay.height(dropTarget.outerHeight());
        overlay.width(dropTarget.outerWidth());
        overlay.position({
            my: 'top left',
            at: 'top left',
            of: dropTarget
        });
    },
    hideDropOverlay: function() {
        var dropTarget = this.getDropTarget(),
            overlay = this.getDropOverlay();
        dropTarget.removeClass('has-overlay');
        overlay.css('display', 'none');
    },

    willDestroyElement: function() {
        var overlay = this.get('dropOverlay'),
            externalInput = this.get('externalInput');
        //Overlay
        if (overlay) {
            overlay.remove();
        }
        //External input
        if (externalInput) {
            externalInput.parent().removeClass('file-uploader-input-parent');
            externalInput.remove();
        }
        //Drop target
        if (this.get('allowDrag')) {
            this.addOrRemoveDropTargetEvents('off');
        }
    },

    enqueue: function(file) {
        var self = this,
            item,
            batch = this.get('batch');
        if (Em.isArray(file)) {
            Array.prototype.forEach.call(file, function(f) {
                this.enqueue(f);
            }, this);
            return;
        }
        if (!this.get('multiple') && this.get('queue.length') > 0) {
            return;
        }
        item = QueueItem.create({
            fileUploader: this,
            file: file
        });
        item.on('upload', function(file, payload) {
            BD.store.sideload(payload);
            self.sendAction('didUploadFile', {
                file: file,
                payload: payload
            });
        });
        item.on('done', function(item) {
            if (self.get('isDestroyed')) {
                return;
            }
            self.removeQueueItem(item);
        });
        this.get('queue').pushObject(item);
        if (batch) {
            batch.pushObject(item);
        }
        manager.enqueue(item);
    },

    removeQueueItem: function(item) {
        this.get('queue').removeObject(item);
    },

    uploadButtonIsVisible: function() {
        return (!this.get('inputSelector') && (this.get('multiple') || this.get('queue.length') === 0));
    }.property('inputSelector', 'multiple', 'queue.@each'),

    queueItemViewClass: require('./queue-item-view')
});

module.exports.Batch = require('./batch');

module.exports.locale = i18nContext.locale;

module.exports.lang = function() {
    console.warn('.lang() is deprecated. Use .locale() instead');
    return i18nContext.locale.apply(null, arguments);
};

module.exports.setHeader = function(key, value) {
    config.headers[key] = value;
};
module.exports.clearHeader = function(key) {
    delete(config.headers[key]);
};
module.exports.clearHeaders = function() {
    config.headers = {};
};
<|endoftext|>


<commit_before>/* =========================================================
 * HappyR Dialog is based on bootstrap modal by Twitter Inc.
 *
 * Documentation and examples is found at http://developer.happyr.se
 *
 * =========================================================
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 <HappyRecruiting, Twitter Inc>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
 * the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 *  THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 *
 * ========================================================= */

!function ($) {

    "use strict"; // jshint ;_;

    $(function () {

        $.support.transition = (function () {

            var transitionEnd = (function () {

                var el = document.createElement('bootstrap');
                var  transEndEventNames = {
                        'WebkitTransition' : 'webkitTransitionEnd',
                        'MozTransition'    : 'transitionend',
                        'OTransition'      : 'oTransitionEnd otransitionend',
                        'transition'       : 'transitionend'
                    };
                var name;

                for (name in transEndEventNames){
                    if (el.style[name] !== undefined) {
                        return transEndEventNames[name]
                    }
                }

            }())

            return transitionEnd && {
                end: transitionEnd
            }

        })()

    })

}(window.jQuery);

!function ($) {

    "use strict"; // jshint ;_;

    /**
     * Constructor for happyr-dialogs
     * @param element
     * @param options
     * @constructor
     */
    var HappyrDialog = function (element, options) {
        this.options = options
        this.$element = $(element);

        this.$element.delegate('[data-dismiss="happyr-dialog"]', 'click.dismiss.happyr-dialog', $.proxy(this.hide, this));

        this.$element.hide();

        //add stuff to the dialog
        happyrDialog_addWrapper(this.$element, options);

        if(this.options.remote){
            var $dialogBody=this.$element.find('.happyr-dialog-body');

            //add loader image
            if(options.loaderImage != undefined){
                $dialogBody.html('')
            }

            $dialogBody.load(this.options.remote, function(){
                if( options.submitFormOnConfirm ){

                    var $form=$('form', $(this));
                    if($form.length>0){
                        $(document).on('happyr-dialog-confirm', function(e){

                            if(options.getFormResultInDialog){
                                $.ajax({
                                    type: $form.attr('method'),
                                    url: $form.attr('action'),
                                    data: $form.serialize(),
                                    success: function (data) {
                                        $dialogBody.html(data);
                                    }
                                });
                            }
                            else if(options.hideAfterFormSubmit){
                                $form.submit();
                                $("#happyr-dialog").happyrDialog('hide');
                            }
                        });
                    }
                }

            });
        }
    }

    HappyrDialog.prototype = {

        constructor: HappyrDialog,

        /**
         * Toggle show/hide
         * @returns {*}
         */
        toggle: function () {
            return this[!this.isShown ? 'show' : 'hide']();
        },

        /**
         * Show dialog
         */
        show: function () {
            var that = this;
            var e = $.Event('show');

            this.$element.trigger(e);

            if (this.isShown || e.isDefaultPrevented()) {
                return;
            }

            this.isShown = true;

            this.escape();

            this.backdrop(function () {
                var transition = $.support.transition && that.$element.hasClass('happyr-dialog-animation')

                if (!that.$element.parent().length) {
                    that.$element.appendTo(document.body); //don't move dialogs dom position
                }

                that.$element.show();

                if (transition) {
                    that.$element[0].offsetWidth; // force reflow
                }

                that.$element
                    .addClass('happyr-dialog-in')
                    .attr('aria-hidden', false);

                that.enforceFocus();

                var triggerShowEvents=function () {
                    that.$element.focus().trigger('shown');
                    $(document).trigger('happyr-dialog-shown');
                };

                transition ?
                    that.$element.one($.support.transition.end, triggerShowEvents) :
                    triggerShowEvents();

            });
        },

        /**
         * Hide dialog
         * @param e
         */
        hide: function (e) {
            e && e.preventDefault();

            var that = this;

            e = $.Event('hide');

            this.$element.trigger(e);

            if (!this.isShown || e.isDefaultPrevented()) return

            this.isShown = false;

            this.escape();

            $(document).off('focusin.happyr-dialog');

            this.$element
                .removeClass('happyr-dialog-in')
                .attr('aria-hidden', true)

            $.support.transition && this.$element.hasClass('happyr-dialog-animation') ?
                this.hideWithTransition() :
                this.hideDialog()
        },

        /**
         * Focus on dialog
         */
        enforceFocus: function () {
            var that = this
            $(document).on('focusin.happyr-dialog', function (e) {
                if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
                    that.$element.focus()
                }
            })
        },

        /**
         * Enable to hide the dialog when escape key is pressed
         */
        escape: function () {
            var that = this
            if (this.isShown && this.options.keyboard) {
                this.$element.on('keyup.dismiss.happyr-dialog', function ( e ) {
                    e.which == 27 && that.hide()
                })
            } else if (!this.isShown) {
                this.$element.off('keyup.dismiss.happyr-dialog')
            }
        },

        /**
         * Hide the dialog with animation
         */
        hideWithTransition: function () {
            var that = this;
            var timeout = setTimeout(function () {
                    that.$element.off($.support.transition.end)
                    that.hideDialog()
                }, 500);

            this.$element.one($.support.transition.end, function () {
                clearTimeout(timeout)
                that.hideDialog()
            })
        },

        /**
         * Hide the dialog
         */
        hideDialog: function () {
            var that = this;
            this.$element.hide();
            this.backdrop(function () {
                that.removeBackdrop()
                that.$element.trigger('hidden')
            })
        },

        /**
         * Remove the backdrop
         */
        removeBackdrop: function () {
            this.$backdrop && this.$backdrop.remove();
            this.$backdrop = null;
        },

        /**
         * Crete the backdrop and run a callback
         * @param callback
         */
        backdrop: function (callback) {
            var that = this;
            var animate = this.$element.hasClass('happyr-dialog-animation') ? 'happyr-dialog-animation' : '';

            if (this.isShown && this.options.backdrop) {
                var doAnimate = $.support.transition && animate;

                this.$backdrop = $('
')
                    .appendTo(document.body);

                this.$backdrop.click(
                    this.options.backdrop == 'static' ?
                        $.proxy(this.$element[0].focus, this.$element[0])
                        : $.proxy(this.hide, this)
                )

                if (doAnimate) {
                    // force reflow
                    this.$backdrop[0].offsetWidth;
                }

                this.$backdrop.addClass('happyr-dialog-in');

                if (!callback){
                    return;
                }

                if(doAnimate){
                    this.$backdrop.one($.support.transition.end, callback);
                }
                else{
                    callback();
                }

            } else if (!this.isShown && this.$backdrop) {
                this.$backdrop.removeClass('happyr-dialog-in')

                if($.support.transition && this.$element.hasClass('happyr-dialog-animation')){
                    this.$backdrop.one($.support.transition.end, callback);
                }
                else{
                    callback();
                }

            } else if (callback) {
                callback()
            }
        }
    }

    // save current dialog impl
    var old = $.fn.happyrDialog

    /**
     * Register the plugin with jQuery and make sure it works as expected
     * @param option
     * @returns {*}
     */
    $.fn.happyrDialog = function (option) {

        return this.each(function () {
            var $this = $(this);
            var data = $this.data('happyrDialog');
            var options = $.extend({}, $.fn.happyrDialog.defaults, $this.data(), typeof option == 'object' && option);

            //if no dialog or not dialog visible
            if(!data || !data.isShown){
                //create dialog
                $this.data('happyrDialog', (data = new HappyrDialog(this, options)))
            }

            if (typeof option == 'string') {
                data[option]();
            }
            else if(option.action != undefined){
                data[option.action]();
            }
            else if (options.show) {
                data.show();
            }
        })
    }

    /**
     * Default options
     */
    $.fn.happyrDialog.defaults = {
        animation: true,
        backdrop: true,
        keyboard: true,
        show: true,
        showHeader: true,
        showFooter: true,
        showCloseButton: 'Close',
        showConfirmButton: 'Confirm',
        showHeaderCloseButton: true,
        showHeaderTitle: true,
        submitFormOnConfirm: true,
        getFormResultInDialog: true,
        hideAfterFormSubmit: false
    }

    $.fn.happyrDialog.Constructor = HappyrDialog

    /**
     * Just ignore if the object is initialized again
     *
     * @returns this
     */
    $.fn.happyrDialog.noConflict = function () {
        $.fn.happyrDialog = old;
        return this;
    }

    /**
     * Auto add dialog if clickable element data-toggle="happyr-dialog" is defined
     */
    $(document).on('click.happyr-dialog.data-api', '[data-toggle="happyr-dialog"]', function (e) {
        var $this = $(this);
        var href = $this.attr('href');
        var $target = $($this.attr('data-target') || (href && !href.match(/[?=]/) && href.replace(/.*(?=#[^\s]+$)/, ''))); //strip for ie7
        var elementSettings=happyrDialog_convertStringToObject($this.attr('data-happyr-dialog-settings'));
        elementSettings=$.extend(
            {
                remote:!/#/.test(href) && href,
                action: 'toggle'
            },
            $target.data(),
            $this.data(),
            elementSettings
        );
        console.log(elementSettings);

        //make sure the button/link does not behave as normal
        e.preventDefault();

        //if no target found
        if($target.length == 0){
            //try to get autogenerated
            $target=$("#happyr-dialog");

            //if target still not found
            if($target.length == 0){
                //Create a target
                $target=$('
')
                    .appendTo(document.body);
            }
        }

        $target
            .happyrDialog(elementSettings)
            .one('hide', function () {
                $this.focus()
            });
    })

    /**
     * Take a string like "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }" and
     * convert it to an object
     *
     * @param string
     * @returns Object
     */
    function happyrDialog_convertStringToObject(string){
        if(string == undefined || string == ""){
            return new Object();
        }
        return JSON.parse(JSON.stringify(eval("("+string+")")));
    }

    /**
     * Add header, footer and content to the dialog
     * @param $element
     * @param options
     */
    function happyrDialog_addWrapper($element,options){
        //save the current content
        var body;
        if($('.happyr-dialog-body',$element).length > 0){
            body=$element.find('.happyr-dialog-body').html();
        }
        else{
            body=$element.html();
        }

        //Clear the contents
        $element.html("");

        //add wrapper
        $element.addClass("happyr-dialog");

        if(options.animation){
            $element.addClass("happyr-dialog-animation");
        }

        if(options.showHeader){
            happyrDialog_addHeader($element,options);
        }

        //add the body
        var $bodyWrapper=$("

").addClass('happyr-dialog-body').append(body);
        $element.append($bodyWrapper)

        if(options.showFooter){
            happyrDialog_addFooter($element,options);
        }
    }

    /**
     * Add a header on the dialog
     *
     * @param $element
     * @param options
     */
    function happyrDialog_addHeader($element,options){
        //start header
        var $header=$("

").addClass('happyr-dialog-header');

        if(options.showHeaderTitle && options.title != undefined){
            //add heading
            var $title=$("
"+options.title+"
");
            $header.append($title);
        }

        if(options.showConfirmButton){
            //add close button
            var $closeButton=$("<button type='button' class='close' data-dismiss='happyr-dialog' aria-hidden='true'>x</button>");
            $header.append($closeButton);
        }

        //add clear fix
        $header.append($("

").addClass("happyr-dialog-clearfix"));

        //end header
        $element.append($header);
    }

    /**
     * Add the footer
     *
     * @param $element
     * @param options
     */
    function happyrDialog_addFooter($element,options){

        var $footer=$("

").addClass('happyr-dialog-footer');

        if(options.showCloseButton){
            //add buttons
            var $closeButton=$("<button class='btn' data-dismiss='happyr-dialog' aria-hidden='true'>"+options.showCloseButton+"</button>");
            $footer.append($closeButton)
        }

        if(options.showConfirmButton){
            var $confirmButton=$("<button class='btn btn-primary'>"+options.showConfirmButton+"</button>");
            $confirmButton.click(function(e){
                $(document).trigger('happyr-dialog-confirm');
            })
            $footer.append($confirmButton);
        }

        $element.append($footer);
    }

}(window.jQuery);
<commit_msg>added bunch of jshint fixes<commit_after>/* =========================================================
 * HappyR Dialog is based on bootstrap modal by Twitter Inc.
 *
 * Documentation and examples is found at http://developer.happyr.se
 *
 * =========================================================
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 <HappyRecruiting, Twitter Inc>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
 * the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 *  THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 *
 * ========================================================= */

!function ($) {

    "use strict"; // jshint ;_;

    $(function () {

        $.support.transition = (function () {

            var transitionEnd = (function () {

                var el = document.createElement('bootstrap');
                var  transEndEventNames = {
                        'WebkitTransition' : 'webkitTransitionEnd',
                        'MozTransition'    : 'transitionend',
                        'OTransition'      : 'oTransitionEnd otransitionend',
                        'transition'       : 'transitionend'
                    };
                var name;

                for (name in transEndEventNames){
                    if (el.style[name] !== undefined) {
                        return transEndEventNames[name];
                    }
                }

            }());

            return transitionEnd && {
                end: transitionEnd
            };

        })();

    });

}(window.jQuery);

!function ($) {

    "use strict"; // jshint ;_;

    /**
     * Constructor for happyr-dialogs
     * @param element
     * @param options
     * @constructor
     */
    var HappyrDialog = function (element, options) {
        this.options = options;
        this.$element = $(element);

        this.$element.delegate('[data-dismiss="happyr-dialog"]', 'click.dismiss.happyr-dialog', $.proxy(this.hide, this));

        this.$element.hide();

        //add stuff to the dialog
        happyrDialog_addWrapper(this.$element, options);

        if(this.options.remote){
            var $dialogBody=this.$element.find('.happyr-dialog-body');

            //add loader image
            if(options.loaderImage !== undefined){
                $dialogBody.html('');
            }

            $dialogBody.load(this.options.remote, function(){
                if( options.submitFormOnConfirm ){

                    var $form=$('form', $(this));
                    if($form.length>0){
                        $(document).on('happyr-dialog-confirm', function(e){

                            if(options.getFormResultInDialog){
                                $.ajax({
                                    type: $form.attr('method'),
                                    url: $form.attr('action'),
                                    data: $form.serialize(),
                                    success: function (data) {
                                        $dialogBody.html(data);
                                    }
                                });
                            }
                            else if(options.hideAfterFormSubmit){
                                $form.submit();
                                $("#happyr-dialog").happyrDialog('hide');
                            }
                        });
                    }
                }

            });
        }
    };

    HappyrDialog.prototype = {

        constructor: HappyrDialog,

        /**
         * Toggle show/hide
         * @returns {*}
         */
        toggle: function () {
            return this[!this.isShown ? 'show' : 'hide']();
        },

        /**
         * Show dialog
         */
        show: function () {
            var that = this;
            var e = $.Event('show');

            this.$element.trigger(e);

            if (this.isShown || e.isDefaultPrevented()) {
                return;
            }

            this.isShown = true;

            this.escape();

            this.backdrop(function () {
                var transition = $.support.transition && that.$element.hasClass('happyr-dialog-animation');

                if (!that.$element.parent().length) {
                    that.$element.appendTo(document.body); //don't move dialogs dom position
                }

                that.$element.show();

                if (transition) {
                    that.$element[0].offsetWidth; // force reflow
                }

                that.$element
                    .addClass('happyr-dialog-in')
                    .attr('aria-hidden', false);

                that.enforceFocus();

                var triggerShowEvents=function () {
                    that.$element.focus().trigger('shown');
                    $(document).trigger('happyr-dialog-shown');
                };

                if(transition){
                    that.$element.one($.support.transition.end, triggerShowEvents());
                }
                else{
                    triggerShowEvents();
                }

            });
        },

        /**
         * Hide dialog
         * @param e
         */
        hide: function (e) {
            if(e){
                e.preventDefault();
            }

            var that = this;

            e = $.Event('hide');

            this.$element.trigger(e);

            if (!this.isShown || e.isDefaultPrevented()) {
                return;
            }

            this.isShown = false;

            this.escape();

            $(document).off('focusin.happyr-dialog');

            this.$element
                .removeClass('happyr-dialog-in')
                .attr('aria-hidden', true);

            if($.support.transition && this.$element.hasClass('happyr-dialog-animation'))
            {
                this.hideWithTransition();
            }
            else{
                this.hideDialog();
            }

        },

        /**
         * Focus on dialog
         */
        enforceFocus: function () {
            var that = this;
            $(document).on('focusin.happyr-dialog', function (e) {
                if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
                    that.$element.focus()
                }
            });
        },

        /**
         * Enable to hide the dialog when escape key is pressed
         */
        escape: function () {
            var that = this
            if (this.isShown && this.options.keyboard) {
                this.$element.on('keyup.dismiss.happyr-dialog', function ( e ) {
                    e.which == 27 && that.hide()
                })
            } else if (!this.isShown) {
                this.$element.off('keyup.dismiss.happyr-dialog')
            }
        },

        /**
         * Hide the dialog with animation
         */
        hideWithTransition: function () {
            var that = this;
            var timeout = setTimeout(function () {
                    that.$element.off($.support.transition.end)
                    that.hideDialog()
                }, 500);

            this.$element.one($.support.transition.end, function () {
                clearTimeout(timeout)
                that.hideDialog()
            })
        },

        /**
         * Hide the dialog
         */
        hideDialog: function () {
            var that = this;
            this.$element.hide();
            this.backdrop(function () {
                that.removeBackdrop()
                that.$element.trigger('hidden')
            })
        },

        /**
         * Remove the backdrop
         */
        removeBackdrop: function () {
            this.$backdrop && this.$backdrop.remove();
            this.$backdrop = null;
        },

        /**
         * Crete the backdrop and run a callback
         * @param callback
         */
        backdrop: function (callback) {
            var that = this;
            var animate = this.$element.hasClass('happyr-dialog-animation') ? 'happyr-dialog-animation' : '';

            if (this.isShown && this.options.backdrop) {
                var doAnimate = $.support.transition && animate;

                this.$backdrop = $('
')
                    .appendTo(document.body);

                this.$backdrop.click(
                    this.options.backdrop == 'static' ?
                        $.proxy(this.$element[0].focus, this.$element[0])
                        : $.proxy(this.hide, this)
                )

                if (doAnimate) {
                    // force reflow
                    this.$backdrop[0].offsetWidth;
                }

                this.$backdrop.addClass('happyr-dialog-in');

                if (!callback){
                    return;
                }

                if(doAnimate){
                    this.$backdrop.one($.support.transition.end, callback);
                }
                else{
                    callback();
                }

            } else if (!this.isShown && this.$backdrop) {
                this.$backdrop.removeClass('happyr-dialog-in');

                if($.support.transition && this.$element.hasClass('happyr-dialog-animation')){
                    this.$backdrop.one($.support.transition.end, callback);
                }
                else{
                    callback();
                }

            } else if (callback) {
                callback();
            }
        }
    };

    // save current dialog impl
    var old = $.fn.happyrDialog;

    /**
     * Register the plugin with jQuery and make sure it works as expected
     * @param option
     * @returns {*}
     */
    $.fn.happyrDialog = function (option) {

        return this.each(function () {
            var $this = $(this);
            var data = $this.data('happyrDialog');
            var options = $.extend({}, $.fn.happyrDialog.defaults, $this.data(), typeof option === 'object' && option);

            //if no dialog or not dialog visible
            if(!data || !data.isShown){
                //create dialog
                $this.data('happyrDialog', (data = new HappyrDialog(this, options)));
            }

            if (typeof option === 'string') {
                data[option]();
            }
            else if(option.action !== undefined){
                data[option.action]();
            }
            else if (options.show) {
                data.show();
            }
        });
    };

    /**
     * Default options
     */
    $.fn.happyrDialog.defaults = {
        animation: true,
        backdrop: true,
        keyboard: true,
        show: true,
        showHeader: true,
        showFooter: true,
        showCloseButton: 'Close',
        showConfirmButton: 'Confirm',
        showHeaderCloseButton: true,
        showHeaderTitle: true,
        submitFormOnConfirm: true,
        getFormResultInDialog: true,
        hideAfterFormSubmit: false
    };

    $.fn.happyrDialog.Constructor = HappyrDialog;

    /**
     * Just ignore if the object is initialized again
     *
     * @returns this
     */
    $.fn.happyrDialog.noConflict = function () {
        $.fn.happyrDialog = old;
        return this;
    };

    /**
     * Auto add dialog if clickable element data-toggle="happyr-dialog" is defined
     */
    $(document).on('click.happyr-dialog.data-api', '[data-toggle="happyr-dialog"]', function (e) {
        var $this = $(this);
        var href = $this.attr('href');
        var $target = $($this.attr('data-target') || (href && !href.match(/[?=]/) && href.replace(/.*(?=#[^\s]+$)/, ''))); //strip for ie7
        var elementSettings=happyrDialog_convertStringToObject($this.attr('data-happyr-dialog-settings'));
        elementSettings=$.extend(
            {
                remote:!/#/.test(href) && href,
                action: 'toggle'
            },
            $target.data(),
            $this.data(),
            elementSettings
        );
        console.log(elementSettings);

        //make sure the button/link does not behave as normal
        e.preventDefault();

        //if no target found
        if($target.length === 0){
            //try to get autogenerated
            $target=$("#happyr-dialog");

            //if target still not found
            if($target.length === 0){
                //Create a target
                $target=$('
')
                    .appendTo(document.body);
            }
        }

        $target
            .happyrDialog(elementSettings)
            .one('hide', function () {
                $this.focus();
            });
    });

    /**
     * Take a string like "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }" and
     * convert it to an object
     *
     * @param string
     * @returns Object
     */
    function happyrDialog_convertStringToObject(string){
        if(string === undefined || string === ""){
            return {};
        }
        return JSON.parse(JSON.stringify(eval("("+string+")")));
    }

    /**
     * Add header, footer and content to the dialog
     * @param $element
     * @param options
     */
    function happyrDialog_addWrapper($element,options){
        //save the current content
        var body;
        if($('.happyr-dialog-body',$element).length > 0){
            body=$element.find('.happyr-dialog-body').html();
        }
        else{
            body=$element.html();
        }

        //Clear the contents
        $element.html("");

        //add wrapper
        $element.addClass("happyr-dialog");

        if(options.animation){
            $element.addClass("happyr-dialog-animation");
        }

        if(options.showHeader){
            happyrDialog_addHeader($element,options);
        }

        //add the body
        var $bodyWrapper=$("

").addClass('happyr-dialog-body').append(body);
        $element.append($bodyWrapper);

        if(options.showFooter){
            happyrDialog_addFooter($element,options);
        }
    }

    /**
     * Add a header on the dialog
     *
     * @param $element
     * @param options
     */
    function happyrDialog_addHeader($element,options){
        //start header
        var $header=$("

").addClass('happyr-dialog-header');

        if(options.showHeaderTitle && options.title !== undefined){
            //add heading
            var $title=$("
"+options.title+"
");
            $header.append($title);
        }

        if(options.showConfirmButton){
            //add close button
            var $closeButton=$("<button type='button' class='close' data-dismiss='happyr-dialog' aria-hidden='true'>x</button>");
            $header.append($closeButton);
        }

        //add clear fix
        $header.append($("

").addClass("happyr-dialog-clearfix"));

        //end header
        $element.append($header);
    }

    /**
     * Add the footer
     *
     * @param $element
     * @param options
     */
    function happyrDialog_addFooter($element,options){

        var $footer=$("

").addClass('happyr-dialog-footer');

        if(options.showCloseButton){
            //add buttons
            var $closeButton=$("<button class='btn' data-dismiss='happyr-dialog' aria-hidden='true'>"+options.showCloseButton+"</button>");
            $footer.append($closeButton);
        }

        if(options.showConfirmButton){
            var $confirmButton=$("<button class='btn btn-primary'>"+options.showConfirmButton+"</button>");
            $confirmButton.click(function(e){
                $(document).trigger('happyr-dialog-confirm');
            });
            $footer.append($confirmButton);
        }

        $element.append($footer);
    }

}(window.jQuery);
<|endoftext|>


<commit_before>import cloneDeep from 'lodash/cloneDeep'
import uuid from 'uuid/v1'
import namespacedUuid from 'uuid/v3'

/**
 * A factory for creating record classes
 *
 * @param {object} [defaults] Default values for when creating a record
 *
 * @return {BaseRecord}       A unique base record class with the defaults accessible
 */
function Record(defaults = {}) {
  function mergeDefaults(props) {
    return {
      ...cloneDeep(defaults),
      ...props,
    }
  }

  /**
   * The base record class has the following capabilities:
   *
   * It tracks changes and knows which properties have changed.
   *
   * It keeps track of whether or not it's been persisted. If a property changes
   * it considers them not persisted.
   *
   * When setting a property to null/undefined, the value is set to the default
   * value rather than null/undefined. you can also use Record.prototype.clear(propName)
   * for the same behavior.
   */
  return class BaseRecord {
    /**
     *
     * @param {object}  props        Initial property values
     * @param {boolean} isPersisted
     */
    constructor(props = {}, isPersisted = false) {
      // a closure variable to track the property definitions
      const propDefinitions = {}

      // setup a closure value to track the property values
      const values = {}

      // the record is persisted if it's not new.
      const privates = {
        __persisted: Boolean(isPersisted || props.__persisted),
        __uuid: props.__uuid || namespacedUuid(`${props.id || Date.now()}`, BaseRecord.namespace()),
      }
      Object.defineProperties(this, {
        __persisted: {
          get() {
            return privates.__persisted
          },
          set(persisted) {
            privates.__persisted = Boolean(persisted)
          },
          enumerable: true,
        },
        __uuid: {
          value: privates.__uuid,
          writeable: false,
          enumerable: true,
        },
        changedProperties: {
          enumerable: false,

          /**
           * @public
           * @instance
           *
           * @return {string[]}  an array of property names that have changed
           */
          value: function() {
            var changes = []
            for (let key in values) {
              ;(function(k) {
                if (values[k].original !== values[k].value) {
                  changes.push(k)
                }
              })(key)
            }
            return changes
          },
        },
        persisted: {
          enumerable: false,

          /**
           * After the record is persisted, called "persisted" with
           * any changed/updated properties on the record. This will
           * set all those updated and then toggle off the persisted flag.
           *
           * @public
           * @instance
           *
           * @param {object} propUpdates
           */
          value: function(propUpdates = {}) {
            // safeguard
            delete propUpdates.__uuid

            // write properties onto the record
            for (let prop in propUpdates) {
              this[prop] = propUpdates[prop]
            }

            // reset the original values to the current state now
            // the record has been persisted.
            for (let prop in this) {
              values[prop].original = this[prop]
            }

            // reset persisted
            this.__persisted = true
          },
        },
      })
      delete props.__uuid
      delete props.__persisted

      // merge in the properties with the default values
      // to get a full data set.
      props = mergeDefaults(props)

      // iterate through the properties
      for (let key in props) {
        // setup closures to preserve the key value as k in each
        ;(function(k) {
          // initialize the value to track the value
          values[k] = {
            original: props[k],
            value: props[k],
          }

          // initialize the prop definition
          propDefinitions[k] = {
            get() {
              return values[k].value
            },
            set(value) {
              // disallow null/undefined -- use default instead
              // note that non-strict equality == matches null and undefined
              value = value == null ? props[k] : value

              // ensure type-safety of the property set. It must match the default
              if (typeof value !== typeof defaults[k]) {
                throw new Error(
                  `Attempting to set property ${key} on the Record with ${value} which is of type ${typeof value}, but expected ${typeof defaults[
                    k
                  ]}`
                )
              }

              // only toggle off persisted if it the value doesn't match
              // otherwise, retain the current value of __persisted
              this.__persisted = value !== values[k].value ? false : this.__persisted

              // apply the value
              values[k].value = value
            },
            enumerable: true,
          }
        }.call(this, key))
      }

      // set the properties on the record
      Object.defineProperties(this, propDefinitions)

      // disallow new properties, deleting properties, etc.
      // Object.freeze(this)
    }

    /**
     * @static
     *
     * @returns {string}  the list class's UUID
     */
    static namespace() {
      return this.uuid || (this.uuid = uuid())
    }

    /**
     * @public
     * @instance
     *
     * @return {string} the list instances uuid
     */
    getUUID() {
      return this.__uuid
    }

    /**
     * @public
     * @instance
     *
     * @returns {boolean}  whether or not the record has unpersisted changes
     */
    hasChanges() {
      return !this.__persisted
    }

    /**
     * Reverts a property to its default value
     *
     * @public
     * @instance
     *
     * @param {string} propName  The property name to revert to default state
     */
    clear(propName) {
      this[propName] = cloneDeep(defaults[propName])
    }

    /**
     * @public
     * @instance
     *
     * @param {string} propName  The property name to see if it exists
     */
    has(propName) {
      return {}.hasOwnProperty.call(this, propName)
    }

    /**
     * @public
     * @instance
     *
     * @param {string} propName  The property name to get
     */
    get(propName) {
      return this[propName]
    }

    /**
     * @public
     * @instance
     *
     * @param  {object}    attrs A set of attributes to apply to the copy
     */
    extend(attrs = {}) {
      Object.assign(this, attrs)
      return this
    }

    /**
     * Return a shallow copy of this object
     */
    toJS() {
      return {
        ...this,
      }
    }
  }
}

export default Record
<commit_msg>Record patch.<commit_after>import cloneDeep from 'lodash/cloneDeep'
import uuid from 'uuid/v1'
import namespacedUuid from 'uuid/v3'

/**
 * A factory for creating record classes
 *
 * @param {object} [defaults] Default values for when creating a record
 *
 * @return {BaseRecord}       A unique base record class with the defaults accessible
 */
function Record(defaults = {}) {
  function mergeDefaults(props) {
    return {
      ...cloneDeep(defaults),
      ...props,
    }
  }

  /**
   * The base record class has the following capabilities:
   *
   * It tracks changes and knows which properties have changed.
   *
   * It keeps track of whether or not it's been persisted. If a property changes
   * it considers them not persisted.
   *
   * When setting a property to null/undefined, the value is set to the default
   * value rather than null/undefined. you can also use Record.prototype.clear(propName)
   * for the same behavior.
   */
  return class BaseRecord {
    /**
     *
     * @param {object}  props        Initial property values
     * @param {boolean} isPersisted
     */
    constructor(props = {}, isPersisted = false) {
      // a closure variable to track the property definitions
      const propDefinitions = {}

      // setup a closure value to track the property values
      const values = {}

      // the record is persisted if it's not new.
      const privates = {
        __persisted: Boolean(isPersisted || props.__persisted),
        __uuid: props.__uuid || namespacedUuid(`${props.id || Date.now()}`, BaseRecord.namespace()),
      }
      Object.defineProperties(this, {
        __persisted: {
          get() {
            return privates.__persisted
          },
          set(persisted) {
            privates.__persisted = Boolean(persisted)
          },
          enumerable: true,
        },
        __uuid: {
          value: privates.__uuid,
          writeable: false,
          enumerable: true,
        },
        changedProperties: {
          enumerable: false,

          /**
           * @public
           * @instance
           *
           * @return {string[]}  an array of property names that have changed
           */
          value: function() {
            var changes = []
            for (let key in values) {
              ;(function(k) {
                if (values[k].original !== values[k].value) {
                  changes.push(k)
                }
              })(key)
            }
            return changes
          },
        },
        persisted: {
          enumerable: false,

          /**
           * After the record is persisted, called "persisted" with
           * any changed/updated properties on the record. This will
           * set all those updated and then toggle off the persisted flag.
           *
           * @public
           * @instance
           *
           * @param {object} propUpdates
           */
          value: function(propUpdates = {}) {
            // safeguard
            delete propUpdates.__uuid

            // write properties onto the record
            for (let prop in propUpdates) {
              this[prop] = propUpdates[prop]
            }

            // reset the original values to the current state now
            // the record has been persisted.
            for (let prop in this) {
              values[prop].original = this[prop]
            }

            // reset persisted
            this.__persisted = true
          },
        },
      })
      delete props.__uuid
      delete props.__persisted

      // merge in the properties with the default values
      // to get a full data set.
      props = mergeDefaults(props)

      // iterate through the properties
      for (let key in props) {
        // setup closures to preserve the key value as k in each
        ;(function(k) {
          // initialize the value to track the value
          values[k] = {
            original: props[k],
            value: props[k],
          }

          // initialize the prop definition
          propDefinitions[k] = {
            get() {
              return values[k].value
            },
            set(value) {
              // disallow null/undefined -- use default instead
              // note that non-strict equality == matches null and undefined
              value = value == null ? props[k] : value

              // ensure type-safety of the property set. It must match the default
              // if (typeof value !== typeof defaults[k]) {
              //   throw new Error(
              //     `Attempting to set property ${key} on the Record with ${value} which is of type ${typeof value}, but expected ${typeof defaults[
              //       k
              //     ]}`
              //   )
              // }

              // only toggle off persisted if it the value doesn't match
              // otherwise, retain the current value of __persisted
              this.__persisted = value !== values[k].value ? false : this.__persisted

              // apply the value
              values[k].value = value
            },
            enumerable: true,
          }
        }.call(this, key))
      }

      // set the properties on the record
      Object.defineProperties(this, propDefinitions)

      // disallow new properties, deleting properties, etc.
      // Object.freeze(this)
    }

    /**
     * @static
     *
     * @returns {string}  the list class's UUID
     */
    static namespace() {
      return this.uuid || (this.uuid = uuid())
    }

    /**
     * @public
     * @instance
     *
     * @return {string} the list instances uuid
     */
    getUUID() {
      return this.__uuid
    }

    /**
     * @public
     * @instance
     *
     * @returns {boolean}  whether or not the record has unpersisted changes
     */
    hasChanges() {
      return !this.__persisted
    }

    /**
     * Reverts a property to its default value
     *
     * @public
     * @instance
     *
     * @param {string} propName  The property name to revert to default state
     */
    clear(propName) {
      this[propName] = cloneDeep(defaults[propName])
    }

    /**
     * @public
     * @instance
     *
     * @param {string} propName  The property name to see if it exists
     */
    has(propName) {
      return {}.hasOwnProperty.call(this, propName)
    }

    /**
     * @public
     * @instance
     *
     * @param {string} propName  The property name to get
     */
    get(propName) {
      return this[propName]
    }

    /**
     * @public
     * @instance
     *
     * @param  {object}    attrs A set of attributes to apply to the copy
     */
    extend(attrs = {}) {
      Object.assign(this, attrs)
      return this
    }

    /**
     * Return a shallow copy of this object
     */
    toJS() {
      return {
        ...this,
      }
    }
  }
}

export default Record
<|endoftext|>