<commit_before>import { each, isString, isFunction, isUndefined, forEach } from 'underscore';
import BrowserParserHtml from './BrowserParserHtml';

export default config => {
  let c = config;
  const modelAttrStart = 'data-gjs-';
  const event = 'parse:html';

  return {
    compTypes: '',

    modelAttrStart,

    /**
     * Extract component props from an attribute object
     * @param {Object} attr
     * @returns {Object} An object containing props and attributes without them
     */
    splitPropsFromAttr(attr = {}) {
      const props = {};
      const attrs = {};

      each(attr, (value, key) => {
        if (key.indexOf(this.modelAttrStart) === 0) {
          const modelAttr = key.replace(modelAttrStart, '');
          const valueLen = value.length;
          const valStr = value && isString(value);
          const firstChar = valStr && value.substr(0, 1);
          const lastChar = valStr && value.substr(valueLen - 1);
          value = value === 'true' ? true : value;
          value = value === 'false' ? false : value;

          // Try to parse JSON where it's possible
          // I can get false positive here (eg. a selector '[data-attr]')
          // so put it under try/catch and let fail silently
          try {
            value =
              (firstChar == '{' && lastChar == '}') || (firstChar == '[' && lastChar == ']')
                ? JSON.parse(value)
                : value;
          } catch (e) {}

          props[modelAttr] = value;
        } else {
          attrs[key] = value;
        }
      });

      return {
        props,
        attrs,
      };
    },

    /**
     * Parse style string to object
     * @param {string} str
     * @return {Object}
     * @example
     * var stl = ParserHtml.parseStyle('color:black; width:100px; test:value;');
     * console.log(stl);
     * // {color: 'black', width: '100px', test: 'value'}
     */
    parseStyle(str) {
      var result = {};
      var decls = str.split(';');
      for (var i = 0, len = decls.length; i < len; i++) {
        var decl = decls[i].trim();
        if (!decl) continue;
        var prop = decl.split(':');
        result[prop[0].trim()] = prop.slice(1).join(':').trim();
      }
      return result;
    },

    /**
     * Parse class string to array
     * @param {string} str
     * @return {Array<string>}
     * @example
     * var res = ParserHtml.parseClass('test1 test2 test3');
     * console.log(res);
     * // ['test1', 'test2', 'test3']
     */
    parseClass(str) {
      const result = [];
      const cls = str.split(' ');
      for (let i = 0, len = cls.length; i < len; i++) {
        const cl = cls[i].trim();
        if (!cl) continue;
        result.push(cl);
      }
      return result;
    },

    /**
     * Get data from the node element
     * @param  {HTMLElement} el DOM element to traverse
     * @return {Array<Object>}
     */
    parseNode(el, opts = {}) {
      const result = [];
      const nodes = el.childNodes;

      for (var i = 0, len = nodes.length; i < len; i++) {
        const node = nodes[i];
        const attrs = node.attributes || [];
        const attrsLen = attrs.length;
        const nodePrev = result[result.length - 1];
        const nodeChild = node.childNodes.length;
        const ct = this.compTypes;
        let model = {};

        // Start with understanding what kind of component it is
        if (ct) {
          let obj = '';
          let type = node.getAttribute && node.getAttribute(`${modelAttrStart}type`);

          // If the type is already defined, use it
          if (type) {
            model = { type };
          } else {
            // Iterate over all available Component Types and
            // the first with a valid result will be that component
            for (let it = 0; it < ct.length; it++) {
              const compType = ct[it];
              obj = compType.model.isComponent(node, opts);

              if (obj) {
                if (typeof obj !== 'object') {
                  obj = { type: compType.id };
                }
                break;
              }
            }

            model = obj;
          }
        }

        // Set tag name if not yet done
        if (!model.tagName) {
          model.tagName = node.tagName ? node.tagName.toLowerCase() : '';
        }

        if (attrsLen) {
          model.attributes = {};
        }

        // Parse attributes
        for (let j = 0; j < attrsLen; j++) {
          const nodeName = attrs[j].nodeName;
          let nodeValue = attrs[j].nodeValue;

          // Isolate attributes
          if (nodeName == 'style') {
            model.style = this.parseStyle(nodeValue);
          } else if (nodeName == 'class') {
            model.classes = this.parseClass(nodeValue);
          } else if (nodeName == 'contenteditable') {
            continue;
          } else if (nodeName.indexOf(modelAttrStart) === 0) {
            const modelAttr = nodeName.replace(modelAttrStart, '');
            const valueLen = nodeValue.length;
            const firstChar = nodeValue && nodeValue.substr(0, 1);
            const lastChar = nodeValue && nodeValue.substr(valueLen - 1);
            nodeValue = nodeValue === 'true' ? true : nodeValue;
            nodeValue = nodeValue === 'false' ? false : nodeValue;

            // Try to parse JSON where it's possible
            // I can get false positive here (eg. a selector '[data-attr]')
            // so put it under try/catch and let fail silently
            try {
              nodeValue =
                (firstChar == '{' && lastChar == '}') || (firstChar == '[' && lastChar == ']')
                  ? JSON.parse(nodeValue)
                  : nodeValue;
            } catch (e) {}

            model[modelAttr] = nodeValue;
          } else {
            // Check for attributes from props (eg. required, disabled)
            if (nodeValue === '' && node[nodeName] === true) {
              nodeValue = true;
            }

            model.attributes[nodeName] = nodeValue;
          }
        }

        // Check for nested elements but avoid it if already provided
        if (nodeChild && !model.components) {
          // Avoid infinite nested text nodes
          const firstChild = node.childNodes[0];

          // If there is only one child and it's a TEXTNODE
          // just make it content of the current node
          if (nodeChild === 1 && firstChild.nodeType === 3) {
            !model.type && (model.type = 'text');
            model.components = {
              type: 'textnode',
              content: firstChild.nodeValue,
            };
          } else {
            model.components = this.parseNode(node, {
              ...opts,
              inSvg: opts.inSvg || model.type === 'svg',
            });
          }
        }

        // Check if it's a text node and if could be moved to the prevous model
        if (model.type == 'textnode') {
          if (nodePrev && nodePrev.type == 'textnode') {
            nodePrev.content += model.content;
            continue;
          }

          // Throw away empty nodes (keep spaces)
          if (!config.keepEmptyTextNodes) {
            const content = node.nodeValue;
            if (content != ' ' && !content.trim()) {
              continue;
            }
          }
        }

        // Check for custom void elements (valid in XML)
        if (!nodeChild && `${node.outerHTML}`.slice(-2) === '/>') {
          model.void = true;
        }

        // If all children are texts and there is some textnode the parent should
        // be text too otherwise I'm unable to edit texnodes
        const comps = model.components;
        if (!model.type && comps) {
          let allTxt = 1;
          let foundTextNode = 0;

          for (let ci = 0; ci < comps.length; ci++) {
            const comp = comps[ci];
            const cType = comp.type;

            if (['text', 'textnode'].indexOf(cType) < 0 && c.textTags.indexOf(comp.tagName) < 0) {
              allTxt = 0;
              break;
            }

            if (cType == 'textnode') {
              foundTextNode = 1;
            }
          }

          if (allTxt && foundTextNode) {
            model.type = 'text';
          }
        }

        // If tagName is still empty and is not a textnode, do not push it
        if (!model.tagName && model.type != 'textnode') {
          continue;
        }

        result.push(model);
      }

      return result;
    },

    /**
     * Parse HTML string to a desired model object
     * @param  {string} str HTML string
     * @param  {ParserCss} parserCss In case there is style tags inside HTML
     * @return {Object}
     */
    parse(str, parserCss, opts = {}) {
      const { em } = c;
      const conf = (em && em.get('Config')) || {};
      const res = { html: null, css: null };
      const cf = { ...config, ...opts };
      const options = {
        ...config.optionsHtml,
        // Support previous `configParser.htmlType` option
        htmlType: config.optionsHtml?.htmlType || config.htmlType,
        ...opts,
      };
      const el = isFunction(cf.parserHtml) ? cf.parserHtml(str, options) : BrowserParserHtml(str, options);
      const scripts = el.querySelectorAll('script');
      let i = scripts.length;

      // Support previous `configMain.allowScripts` option
      const allowScripts = !isUndefined(conf.allowScripts) ? conf.allowScripts : options.allowScripts;

      // Remove script tags
      if (!allowScripts) {
        while (i--) scripts[i].parentNode.removeChild(scripts[i]);
      }

      // Remove unsafe attributes
      if (!options.allowUnsafeAttr) {
        this.__clearUnsafeAttr(el);
      }

      // Detach style tags and parse them
      if (parserCss) {
        const styles = el.querySelectorAll('style');
        let j = styles.length;
        let styleStr = '';

        while (j--) {
          styleStr = styles[j].innerHTML + styleStr;
          styles[j].parentNode.removeChild(styles[j]);
        }

        if (styleStr) res.css = parserCss.parse(styleStr);
      }

      em && em.trigger(`${event}:root`, { input: str, root: el });
      const result = this.parseNode(el);
      // I have to keep it otherwise it breaks the DomComponents.addComponent (returns always array)
      const resHtml = result.length === 1 && !c.returnArray ? result[0] : result;
      res.html = resHtml;
      em && em.trigger(event, { input: str, output: res });

      return res;
    },

    __clearUnsafeAttr(node) {
      const attrs = node.attributes || [];
      const nodes = node.childNodes || [];
      forEach(attrs, attr => {
        const name = attr.nodeName || '';
        name.indexOf('on') === 0 && node.removeAttribute(name);
      });
      forEach(nodes, node => this.__clearUnsafeAttr(node));
    },
  };
};
<commit_msg>Update clean attr<commit_after>import { each, isString, isFunction, isUndefined } from 'underscore';
import BrowserParserHtml from './BrowserParserHtml';

export default config => {
  let c = config;
  const modelAttrStart = 'data-gjs-';
  const event = 'parse:html';

  return {
    compTypes: '',

    modelAttrStart,

    /**
     * Extract component props from an attribute object
     * @param {Object} attr
     * @returns {Object} An object containing props and attributes without them
     */
    splitPropsFromAttr(attr = {}) {
      const props = {};
      const attrs = {};

      each(attr, (value, key) => {
        if (key.indexOf(this.modelAttrStart) === 0) {
          const modelAttr = key.replace(modelAttrStart, '');
          const valueLen = value.length;
          const valStr = value && isString(value);
          const firstChar = valStr && value.substr(0, 1);
          const lastChar = valStr && value.substr(valueLen - 1);
          value = value === 'true' ? true : value;
          value = value === 'false' ? false : value;

          // Try to parse JSON where it's possible
          // I can get false positive here (eg. a selector '[data-attr]')
          // so put it under try/catch and let fail silently
          try {
            value =
              (firstChar == '{' && lastChar == '}') || (firstChar == '[' && lastChar == ']')
                ? JSON.parse(value)
                : value;
          } catch (e) {}

          props[modelAttr] = value;
        } else {
          attrs[key] = value;
        }
      });

      return {
        props,
        attrs,
      };
    },

    /**
     * Parse style string to object
     * @param {string} str
     * @return {Object}
     * @example
     * var stl = ParserHtml.parseStyle('color:black; width:100px; test:value;');
     * console.log(stl);
     * // {color: 'black', width: '100px', test: 'value'}
     */
    parseStyle(str) {
      var result = {};
      var decls = str.split(';');
      for (var i = 0, len = decls.length; i < len; i++) {
        var decl = decls[i].trim();
        if (!decl) continue;
        var prop = decl.split(':');
        result[prop[0].trim()] = prop.slice(1).join(':').trim();
      }
      return result;
    },

    /**
     * Parse class string to array
     * @param {string} str
     * @return {Array<string>}
     * @example
     * var res = ParserHtml.parseClass('test1 test2 test3');
     * console.log(res);
     * // ['test1', 'test2', 'test3']
     */
    parseClass(str) {
      const result = [];
      const cls = str.split(' ');
      for (let i = 0, len = cls.length; i < len; i++) {
        const cl = cls[i].trim();
        if (!cl) continue;
        result.push(cl);
      }
      return result;
    },

    /**
     * Get data from the node element
     * @param  {HTMLElement} el DOM element to traverse
     * @return {Array<Object>}
     */
    parseNode(el, opts = {}) {
      const result = [];
      const nodes = el.childNodes;

      for (var i = 0, len = nodes.length; i < len; i++) {
        const node = nodes[i];
        const attrs = node.attributes || [];
        const attrsLen = attrs.length;
        const nodePrev = result[result.length - 1];
        const nodeChild = node.childNodes.length;
        const ct = this.compTypes;
        let model = {};

        // Start with understanding what kind of component it is
        if (ct) {
          let obj = '';
          let type = node.getAttribute && node.getAttribute(`${modelAttrStart}type`);

          // If the type is already defined, use it
          if (type) {
            model = { type };
          } else {
            // Iterate over all available Component Types and
            // the first with a valid result will be that component
            for (let it = 0; it < ct.length; it++) {
              const compType = ct[it];
              obj = compType.model.isComponent(node, opts);

              if (obj) {
                if (typeof obj !== 'object') {
                  obj = { type: compType.id };
                }
                break;
              }
            }

            model = obj;
          }
        }

        // Set tag name if not yet done
        if (!model.tagName) {
          model.tagName = node.tagName ? node.tagName.toLowerCase() : '';
        }

        if (attrsLen) {
          model.attributes = {};
        }

        // Parse attributes
        for (let j = 0; j < attrsLen; j++) {
          const nodeName = attrs[j].nodeName;
          let nodeValue = attrs[j].nodeValue;

          // Isolate attributes
          if (nodeName == 'style') {
            model.style = this.parseStyle(nodeValue);
          } else if (nodeName == 'class') {
            model.classes = this.parseClass(nodeValue);
          } else if (nodeName == 'contenteditable') {
            continue;
          } else if (nodeName.indexOf(modelAttrStart) === 0) {
            const modelAttr = nodeName.replace(modelAttrStart, '');
            const valueLen = nodeValue.length;
            const firstChar = nodeValue && nodeValue.substr(0, 1);
            const lastChar = nodeValue && nodeValue.substr(valueLen - 1);
            nodeValue = nodeValue === 'true' ? true : nodeValue;
            nodeValue = nodeValue === 'false' ? false : nodeValue;

            // Try to parse JSON where it's possible
            // I can get false positive here (eg. a selector '[data-attr]')
            // so put it under try/catch and let fail silently
            try {
              nodeValue =
                (firstChar == '{' && lastChar == '}') || (firstChar == '[' && lastChar == ']')
                  ? JSON.parse(nodeValue)
                  : nodeValue;
            } catch (e) {}

            model[modelAttr] = nodeValue;
          } else {
            // Check for attributes from props (eg. required, disabled)
            if (nodeValue === '' && node[nodeName] === true) {
              nodeValue = true;
            }

            model.attributes[nodeName] = nodeValue;
          }
        }

        // Check for nested elements but avoid it if already provided
        if (nodeChild && !model.components) {
          // Avoid infinite nested text nodes
          const firstChild = node.childNodes[0];

          // If there is only one child and it's a TEXTNODE
          // just make it content of the current node
          if (nodeChild === 1 && firstChild.nodeType === 3) {
            !model.type && (model.type = 'text');
            model.components = {
              type: 'textnode',
              content: firstChild.nodeValue,
            };
          } else {
            model.components = this.parseNode(node, {
              ...opts,
              inSvg: opts.inSvg || model.type === 'svg',
            });
          }
        }

        // Check if it's a text node and if could be moved to the prevous model
        if (model.type == 'textnode') {
          if (nodePrev && nodePrev.type == 'textnode') {
            nodePrev.content += model.content;
            continue;
          }

          // Throw away empty nodes (keep spaces)
          if (!config.keepEmptyTextNodes) {
            const content = node.nodeValue;
            if (content != ' ' && !content.trim()) {
              continue;
            }
          }
        }

        // Check for custom void elements (valid in XML)
        if (!nodeChild && `${node.outerHTML}`.slice(-2) === '/>') {
          model.void = true;
        }

        // If all children are texts and there is some textnode the parent should
        // be text too otherwise I'm unable to edit texnodes
        const comps = model.components;
        if (!model.type && comps) {
          let allTxt = 1;
          let foundTextNode = 0;

          for (let ci = 0; ci < comps.length; ci++) {
            const comp = comps[ci];
            const cType = comp.type;

            if (['text', 'textnode'].indexOf(cType) < 0 && c.textTags.indexOf(comp.tagName) < 0) {
              allTxt = 0;
              break;
            }

            if (cType == 'textnode') {
              foundTextNode = 1;
            }
          }

          if (allTxt && foundTextNode) {
            model.type = 'text';
          }
        }

        // If tagName is still empty and is not a textnode, do not push it
        if (!model.tagName && model.type != 'textnode') {
          continue;
        }

        result.push(model);
      }

      return result;
    },

    /**
     * Parse HTML string to a desired model object
     * @param  {string} str HTML string
     * @param  {ParserCss} parserCss In case there is style tags inside HTML
     * @return {Object}
     */
    parse(str, parserCss, opts = {}) {
      const { em } = c;
      const conf = (em && em.get('Config')) || {};
      const res = { html: null, css: null };
      const cf = { ...config, ...opts };
      const options = {
        ...config.optionsHtml,
        // Support previous `configParser.htmlType` option
        htmlType: config.optionsHtml?.htmlType || config.htmlType,
        ...opts,
      };
      const el = isFunction(cf.parserHtml) ? cf.parserHtml(str, options) : BrowserParserHtml(str, options);
      const scripts = el.querySelectorAll('script');
      let i = scripts.length;

      // Support previous `configMain.allowScripts` option
      const allowScripts = !isUndefined(conf.allowScripts) ? conf.allowScripts : options.allowScripts;

      // Remove script tags
      if (!allowScripts) {
        while (i--) scripts[i].parentNode.removeChild(scripts[i]);
      }

      // Remove unsafe attributes
      if (!options.allowUnsafeAttr) {
        this.__clearUnsafeAttr(el);
      }

      // Detach style tags and parse them
      if (parserCss) {
        const styles = el.querySelectorAll('style');
        let j = styles.length;
        let styleStr = '';

        while (j--) {
          styleStr = styles[j].innerHTML + styleStr;
          styles[j].parentNode.removeChild(styles[j]);
        }

        if (styleStr) res.css = parserCss.parse(styleStr);
      }

      em && em.trigger(`${event}:root`, { input: str, root: el });
      const result = this.parseNode(el);
      // I have to keep it otherwise it breaks the DomComponents.addComponent (returns always array)
      const resHtml = result.length === 1 && !c.returnArray ? result[0] : result;
      res.html = resHtml;
      em && em.trigger(event, { input: str, output: res });

      return res;
    },

    __clearUnsafeAttr(node) {
      const attrs = node.attributes || [];
      const nodes = node.childNodes || [];
      const toRemove = [];
      each(attrs, attr => {
        const name = attr.nodeName || '';
        name.indexOf('on') === 0 && toRemove.push(name);
      });
      toRemove.map(name => node.removeAttribute(name));
      each(nodes, node => this.__clearUnsafeAttr(node));
    },
  };
};
<|endoftext|>


<commit_before>/* version 0.2.12 */
oldmansoft.webapp.extend = {};
oldmansoft.webapp.extend.form_verify = function (form) {
	function checkReady() {
		var valid = true,
            checkedInput = {};
		form.find("input,textarea").each(function () {
			var $input = $(this),
                verify = $input.attr("data-verify");
			if (!verify) return;
			if (verify.indexOf("required") > -1) {
				if ($input.attr("type") == "radio" || $input.attr("type") == "checkbox") {
					if ($input.prop("checked")) {
					    checkedInput[$input.attr("name")] = true;
					} else if (checkedInput[$input.attr("name")] == undefined) {
					    checkedInput[$input.attr("name")] = false;
					}
				} else if ($.trim($input.val()) == "") {
					valid = false;
					return false;
				}
			}
		});
		for (var item in checkedInput) {
		    if (checkedInput[item] == false) {
				valid = false;
				form.find("input[name=" + item + "]").parent().addClass("verify-invalid");
		    } else {
		        form.find("input[name=" + item + "]").parent().removeClass("verify-invalid");
		    }
		}

		if (form.data("verify").has()) valid = false;

		if (valid) {
			if (form.hasClass("not-ready")) {
				form.removeClass("not-ready");
				form.trigger("change");
			}
		} else {
			if (!form.hasClass("not-ready")) {
				form.addClass("not-ready");
				form.trigger("change");
			}
		}
	}

	if (form.length == 0) return;
	if (form.find("[data-verify]").length == 0) return;

	form.data("verify", new function () {
		var items = [];
		this.add = function (item) {
			for (var i = 0; i < items.length; i++) {
				if (items[i] == item) return;
			}
			items.push(item);
			checkReady();
		}
		this.remove = function (item) {
			for (var i = 0; i < items.length; i++) {
				if (items[i] == item) {
					items.splice(i, 1);
					checkReady();
					return;
				}
			}
		}
		this.has = function () {
			return items.length > 0;
		}
	});
	form.find("input,textarea").each(function () {
		var $input = $(this),
            verify = $input.attr("data-verify");
		if (!verify) return;
		$input.on("change keyup", checkReady);
	});
	form.data("check", checkReady);
	checkReady();
}

oldmansoft.webapp.extend.deal = new function () {
	var result;
	function action() {
		if (result.script) {
			eval(result.script);
		}

		if (result.redirect) {
			$app.same(result.redirect);
		} else if (result.refresh) {
			$app.reload();
		}
	}

	function close() {
		if (result.close) {
		    $app.close().completed(action);
			return;
		}
		action();
	}

	this.execute = function (service) {
		result = service;
		if (service.message != null) {
			$app.alert(service.message).ok(function () {
				close();
			});
			return;
		}
		close();
	}
}

oldmansoft.webapp.extend.link_script_click = function () {
    var link = $(this),
        confirmCall = link.attr("data-confirm-call"),
        confirm = link.attr("data-confirm"),
        call = link.attr("data-call");
    function click() {
        var loading;
        if (call) eval(call);
        loading = $app.loading();
        $.ajax({
            url: link.attr("href"),
            type: "POST"
        }).done(function (result) {
            loading.hide();
            oldmansoft.webapp.extend.deal.execute(result);
        }).fail(function (error) {
            loading.hide();
            alert(error.statusText);
        });
    }
    if (link.hasClass("disabled")) return false;
    if (confirmCall) {
        var confirmContent = eval(confirmCall);
        if (confirmContent) {
            $app.confirm(confirmContent, "请确认").yes(click);
        } else {
            click();
        }
    } else if (confirm) {
        $app.confirm(confirm, "请确认").yes(click);
    } else {
        click();
    }
    return false;
}

oldmansoft.webapp.extend.form_auto_submit = function() {
    var form = $(this),
        result;

	function dealAction() {
		if (result.script) {
			eval(result.script);
		}

		if (result.redirect) {
			$app.same(result.redirect);
		} else if (result.refresh) {
			$app.reload();
		}
	}
	function dealClose() {
		if (result.close) {
		    $app.close().completed(dealAction);
			return;
		}
		dealAction();
	}

	function GetFormData(form, formData) {
	    form.find("input[type!=file]").each(function () {
	        var $this = $(this);
	        if (!$this.attr("name")) return;
	        if ($this.prop("readonly") || $this.prop("disabled")) return;
	        if ($this.attr("type") == "checkbox" || $this.attr("type") == "radio") {
	            if (!$this.prop("checked")) return;
	        }
	        formData.append($this.attr("name"), $this.val());
	    });
	    form.find("input[type=file]").each(function () {
	        var $this = $(this);
	        if (!$this.attr("name")) return;
	        if ($this.prop("readonly") || $this.prop("disabled")) return;
	        if ($this.data("images")) {
	            for (var i = 0; i < $this.get(0).files.length; i++) {
	                formData.append($this.attr("name"), $this.data("images")[i], $this.get(0).files[i].name);
	            }
	        } else {
	            if ($this.get(0).files.length == 0) {
	                formData.append($this.attr("name"), new Blob([], { type: "application/octet-stream" }), "");
	            }
	            for (var i = 0 ; i < $this.get(0).files.length; i++) {
	                formData.append($this.attr("name"), $this.get(0).files[i], $this.get(0).files[i].name);
	            }
	        }
	    });
	    form.find("select").each(function () {
	        var $this = $(this);
	        if (!$this.attr("name")) return;
	        if ($this.prop("readonly") || $this.prop("disabled")) return;
	        formData.append($this.attr("name"), $this.val());
	    });
	    form.find("textarea").each(function () {
	        var $this = $(this);
	        if (!$this.attr("name")) return;
	        if ($this.prop("readonly") || $this.prop("disabled")) return;
	        formData.append($this.attr("name"), $this.val());
	    });
	}

	function ImageDealSubmit(form) {
	    var formData = new FormData();
	    GetFormData(form, formData);

	    var result = $.ajax({
	        url: form.attr("action"),
	        type: "POST",
	        xhr: function () {
	            return $.ajaxSettings.xhr();
	        },
	        data: formData,
	        contentType: false,
	        processData: false
	    });
	    return result;
	}

	var FormGetSubmit = function (form) {
	    var data = new (function () {
	        var content = [];
	        this.append = function (name, value) {
	            content.push(encodeURIComponent(name) + "=" + encodeURIComponent(value));
	        }
	        this.get = function (splitChar) {
	            if (content.length == 0) return "";
	            return splitChar + content.join("&");
	        }
	    })();
	    GetFormData(form, data);
	    if (form.attr("target") && oldmansoft.webapp.getDealHrefTarget()[form.attr("target")]) {
	        oldmansoft.webapp.getDealHrefTarget()[form.attr("target")](form.attr("action") + data.get(form.attr("action").indexOf("?") > -1 ? "&" : "?"))
	    } else {
	        $app.link(form.attr("action") + data.get(form.attr("action").indexOf("?") > -1 ? "&" : "?"));
	    }
	}

	function submitForm() {
		var loading,
            submit = null;
		if (form.attr("data-script")) {
		    submit = eval(form.attr("data-script"));
		    return;
		} else if (!form.attr("method") || form.attr("method").toLowerCase() != "post") {
			FormGetSubmit(form);
			return;
		}

		loading = $app.loading();
		if (form.hasClass("image-deal")) {
			submit = ImageDealSubmit(form);
		} else {
			submit = form.ajaxSubmit().data("jqxhr");
		}
		submit.done(function (service) {
			loading.hide();
			result = service;
			if (service.message != null) {
				$app.alert(service.message).ok(function () {
					dealClose();
				});
				return;
			}
			dealClose();
		}).fail(function (error) {
			loading.hide();
			$app.alert($(error.responseText).eq(1).text(), error.statusText);
		});
	}

	if (form.hasClass("not-ready")) return false;
	if (form.hasClass("disabled")) return false;
	if (form.attr("data-confirm-call")) {
		var confirmContent = eval(form.attr("data-confirm-call"));
		if (confirmContent) {
			$app.confirm(confirmContent, "请确认").yes(submitForm);
		} else {
			submitForm();
		}
	} else if (form.attr("data-confirm")) {
		$app.confirm(form.attr("data-confirm"), "请确认").yes(submitForm);
	} else {
		submitForm();
	}

	return false;
}

jQuery.fn.extend({
	imageDeal: function (finish, start) {
		function dataURL2Blob(dataurl) {
			var arr = dataurl.split(','),
                mime = arr[0].match(/:(.*?);/)[1],
                bstr = atob(arr[1]),
                n = bstr.length,
                u8arr = new Uint8Array(n);
			while (n--) {
				u8arr[n] = bstr.charCodeAt(n);
			}
			return new Blob([u8arr], { type: mime });
		}

		function completed(element, file, message) {
		    var done = $(element).data("done") + 1;
		    $(element).data("done", done);
		    if (done == element.files.length) {
		        message.close();
		        if (finish) finish(file);
		        $(element).trigger("dealt");
		    }
		}

		function render(dataUrl, file, element, message, width, height, deal) {
			var image = new Image();
			image.onload = function () {
				var canvas,
                    ctx,
				    blob;

				if (image.width <= width && image.height <= height) {
				    blob = file;
				} else {
				    canvas = document.createElement("canvas");
				    ctx = canvas.getContext("2d");
				    if (deal == "cut") {
				        if (image.width <= image.height && image.width > width) {
				            image.height *= width / image.width;
				            image.width = width;
				        } else if (image.width >= image.height && image.height > height) {
				            image.width *= height / image.height;
				            image.height = height;
				        }
				        canvas.width = image.width > width ? width : image.width;
				        canvas.height = image.height > height ? height : image.height;
				    } else {
				        if (image.width >= image.height && image.width > width) {
				            image.height *= width / image.width;
				            image.width = width;
				        } else if (image.width <= image.height && image.height > height) {
				            image.width *= height / image.height;
				            image.height = height;
				        }
				        canvas.width = image.width;
				        canvas.height = image.height;
				    }
				    ctx.drawImage(image, 0, 0, image.width, image.height);
				    blob = file.type == "image/jpeg" ? dataURL2Blob(canvas.toDataURL("image/jpeg", 0.95)) : dataURL2Blob(canvas.toDataURL(file.type));
				}

				if (!$(element).data("images")) $(element).data("images", []);
				$(element).data("images").push(blob);
				completed(element, file, message);
			};
			image.src = dataUrl;
		}

		function loadImage(file, element, message, width, height, deal) {
			if (!file.type.match(/image.*/)) {
				window.alert("只能选择图片文件");
				return;
			}
			var reader = new FileReader();

			reader.onload = function (e) {
			    render(e.target.result, file, element, message, width, height, deal);
			};
			reader.readAsDataURL(file);
		}
		var width = this.attr("data-width"),
            height = this.attr("data-height"),
            deal = this.attr("data-deal");

		if (width && height) {
			this.on("change", function () {
			    $(this).data("images", null);
			    $(this).data("done", 0);
			    if (start) start();
			    $(this).trigger("dealing");
				if (this.files.length == 0) {
					if (finish) finish(null);
					$(element).trigger("dealt");
					return;
				}
				var message = $app.message("图片处理中")
				for (var i = 0; i < this.files.length; i++) {
				    loadImage(this.files[i], this, message, Number(width), Number(height), deal);
				}
			});
		}
		return this;
	}
});

oldmansoft.webapp.initialled(function () {
    $(document).on("submit", "form.auto", oldmansoft.webapp.extend.form_auto_submit);
    $(document).on("click", "a[target=_script]", oldmansoft.webapp.extend.link_script_click);
	$app.option().viewLoaded(function (view) {
	    view.node.find("form.auto input[type=file][data-width][data-height]").each(function () {
			var $this = $(this);
			$this.imageDeal(function (file) {
			    $this.parentsUntil("body", "form").addClass("image-deal");
			    if ($this.hasClass("file-input")) $this.next().text(file == null ? "" : file.name);
			}).on("dealing", function () {
			    if ($this.hasClass("file-input")) $this.next().text("处理中...");
			});
			if ($this.hasClass("file-input")) {
			    $this.next().click(function () {
			        $this.click();
			    });
			}
	    });

	    view.node.find("form").each(function () {
	        oldmansoft.webapp.extend.form_verify($(this));
	    });
	});
});<commit_msg>调整图片上传表单的处理逻辑。<commit_after>/* version 0.2.13 */
oldmansoft.webapp.extend = {};
oldmansoft.webapp.extend.form_verify = function (form) {
	function checkReady() {
		var valid = true,
            checkedInput = {};
		form.find("input,textarea").each(function () {
			var $input = $(this),
                verify = $input.attr("data-verify");
			if (!verify) return;
			if (verify.indexOf("required") > -1) {
				if ($input.attr("type") == "radio" || $input.attr("type") == "checkbox") {
					if ($input.prop("checked")) {
					    checkedInput[$input.attr("name")] = true;
					} else if (checkedInput[$input.attr("name")] == undefined) {
					    checkedInput[$input.attr("name")] = false;
					}
				} else if ($.trim($input.val()) == "") {
					valid = false;
					return false;
				}
			}
		});
		for (var item in checkedInput) {
		    if (checkedInput[item] == false) {
				valid = false;
				form.find("input[name=" + item + "]").parent().addClass("verify-invalid");
		    } else {
		        form.find("input[name=" + item + "]").parent().removeClass("verify-invalid");
		    }
		}

		if (form.data("verify").has()) valid = false;

		if (valid) {
			if (form.hasClass("not-ready")) {
				form.removeClass("not-ready");
				form.trigger("change");
			}
		} else {
			if (!form.hasClass("not-ready")) {
				form.addClass("not-ready");
				form.trigger("change");
			}
		}
	}

	if (form.length == 0) return;
	if (form.find("[data-verify]").length == 0) return;

	form.data("verify", new function () {
		var items = [];
		this.add = function (item) {
			for (var i = 0; i < items.length; i++) {
				if (items[i] == item) return;
			}
			items.push(item);
			checkReady();
		}
		this.remove = function (item) {
			for (var i = 0; i < items.length; i++) {
				if (items[i] == item) {
					items.splice(i, 1);
					checkReady();
					return;
				}
			}
		}
		this.has = function () {
			return items.length > 0;
		}
	});
	form.find("input,textarea").each(function () {
		var $input = $(this),
            verify = $input.attr("data-verify");
		if (!verify) return;
		$input.on("change keyup", checkReady);
	});
	form.data("check", checkReady);
	checkReady();
}

oldmansoft.webapp.extend.deal = new function () {
	var result;
	function action() {
		if (result.script) {
			eval(result.script);
		}

		if (result.redirect) {
			$app.same(result.redirect);
		} else if (result.refresh) {
			$app.reload();
		}
	}

	function close() {
		if (result.close) {
		    $app.close().completed(action);
			return;
		}
		action();
	}

	this.execute = function (service) {
		result = service;
		if (service.message != null) {
			$app.alert(service.message).ok(function () {
				close();
			});
			return;
		}
		close();
	}
}

oldmansoft.webapp.extend.link_script_click = function () {
    var link = $(this),
        confirmCall = link.attr("data-confirm-call"),
        confirm = link.attr("data-confirm"),
        call = link.attr("data-call");
    function click() {
        var loading;
        if (call) eval(call);
        loading = $app.loading();
        $.ajax({
            url: link.attr("href"),
            type: "POST"
        }).done(function (result) {
            loading.hide();
            oldmansoft.webapp.extend.deal.execute(result);
        }).fail(function (error) {
            loading.hide();
            alert(error.statusText);
        });
    }
    if (link.hasClass("disabled")) return false;
    if (confirmCall) {
        var confirmContent = eval(confirmCall);
        if (confirmContent) {
            $app.confirm(confirmContent, "请确认").yes(click);
        } else {
            click();
        }
    } else if (confirm) {
        $app.confirm(confirm, "请确认").yes(click);
    } else {
        click();
    }
    return false;
}

oldmansoft.webapp.extend.form_auto_submit = function() {
    var form = $(this),
        result;

	function dealAction() {
		if (result.script) {
			eval(result.script);
		}

		if (result.redirect) {
			$app.same(result.redirect);
		} else if (result.refresh) {
			$app.reload();
		}
	}
	function dealClose() {
		if (result.close) {
		    $app.close().completed(dealAction);
			return;
		}
		dealAction();
	}

	function GetFormData(form, formData) {
	    form.find("input[type!=file]").each(function () {
	        var $this = $(this);
	        if (!$this.attr("name")) return;
	        if ($this.prop("readonly") || $this.prop("disabled")) return;
	        if ($this.attr("type") == "checkbox" || $this.attr("type") == "radio") {
	            if (!$this.prop("checked")) return;
	        }
	        formData.append($this.attr("name"), $this.val());
	    });
	    form.find("input[type=file]").each(function () {
	        var $this = $(this);
	        if (!$this.attr("name")) return;
	        if ($this.prop("readonly") || $this.prop("disabled")) return;
	        if ($this.data("images")) {
	            for (var i = 0; i < $this.data("images").length; i++) {
	                formData.append($this.attr("name"), $this.data("images")[i].blob, $this.data("images")[i].name);
	            }
	        } else {
	            if ($this.get(0).files.length == 0) {
	                formData.append($this.attr("name"), new Blob([], { type: "application/octet-stream" }), "");
	            }
	            for (var i = 0 ; i < $this.get(0).files.length; i++) {
	                formData.append($this.attr("name"), $this.get(0).files[i], $this.get(0).files[i].name);
	            }
	        }
	    });
	    form.find("select").each(function () {
	        var $this = $(this);
	        if (!$this.attr("name")) return;
	        if ($this.prop("readonly") || $this.prop("disabled")) return;
	        formData.append($this.attr("name"), $this.val());
	    });
	    form.find("textarea").each(function () {
	        var $this = $(this);
	        if (!$this.attr("name")) return;
	        if ($this.prop("readonly") || $this.prop("disabled")) return;
	        formData.append($this.attr("name"), $this.val());
	    });
	}

	function ImageDealSubmit(form) {
	    var formData = new FormData();
	    GetFormData(form, formData);

	    var result = $.ajax({
	        url: form.attr("action"),
	        type: "POST",
	        xhr: function () {
	            return $.ajaxSettings.xhr();
	        },
	        data: formData,
	        contentType: false,
	        processData: false
	    });
	    return result;
	}

	var FormGetSubmit = function (form) {
	    var data = new (function () {
	        var content = [];
	        this.append = function (name, value) {
	            content.push(encodeURIComponent(name) + "=" + encodeURIComponent(value));
	        }
	        this.get = function (splitChar) {
	            if (content.length == 0) return "";
	            return splitChar + content.join("&");
	        }
	    })();
	    GetFormData(form, data);
	    if (form.attr("target") && oldmansoft.webapp.getDealHrefTarget()[form.attr("target")]) {
	        oldmansoft.webapp.getDealHrefTarget()[form.attr("target")](form.attr("action") + data.get(form.attr("action").indexOf("?") > -1 ? "&" : "?"))
	    } else {
	        $app.link(form.attr("action") + data.get(form.attr("action").indexOf("?") > -1 ? "&" : "?"));
	    }
	}

	function submitForm() {
		var loading,
            submit = null;
		if (form.attr("data-script")) {
		    submit = eval(form.attr("data-script"));
		    return;
		} else if (!form.attr("method") || form.attr("method").toLowerCase() != "post") {
			FormGetSubmit(form);
			return;
		}

		loading = $app.loading();
		if (form.hasClass("image-deal")) {
			submit = ImageDealSubmit(form);
		} else {
			submit = form.ajaxSubmit().data("jqxhr");
		}
		submit.done(function (service) {
			loading.hide();
			result = service;
			if (service.message != null) {
				$app.alert(service.message).ok(function () {
					dealClose();
				});
				return;
			}
			dealClose();
		}).fail(function (error) {
			loading.hide();
			$app.alert($(error.responseText).eq(1).text(), error.statusText);
		});
	}

	if (form.hasClass("not-ready")) return false;
	if (form.hasClass("disabled")) return false;
	if (form.attr("data-confirm-call")) {
		var confirmContent = eval(form.attr("data-confirm-call"));
		if (confirmContent) {
			$app.confirm(confirmContent, "请确认").yes(submitForm);
		} else {
			submitForm();
		}
	} else if (form.attr("data-confirm")) {
		$app.confirm(form.attr("data-confirm"), "请确认").yes(submitForm);
	} else {
		submitForm();
	}

	return false;
}

jQuery.fn.extend({
	imageDeal: function (finish, start) {
		function dataURL2Blob(dataurl) {
			var arr = dataurl.split(','),
                mime = arr[0].match(/:(.*?);/)[1],
                bstr = atob(arr[1]),
                n = bstr.length,
                u8arr = new Uint8Array(n);
			while (n--) {
				u8arr[n] = bstr.charCodeAt(n);
			}
			return new Blob([u8arr], { type: mime });
		}

		function completed(element, file, message) {
		    if ($(element).data("images").length == element.files.length) {
		        message.close();
		        if (finish) finish(file);
		        $(element).trigger("dealt");
		    }
		}

		function render(dataUrl, file, element, message, width, height, deal) {
			var image = new Image();
			image.onload = function () {
				var canvas,
                    ctx,
				    blob;

				if (image.width <= width && image.height <= height) {
				    blob = file;
				} else {
				    canvas = document.createElement("canvas");
				    ctx = canvas.getContext("2d");
				    if (deal == "cut") {
				        if (image.width <= image.height && image.width > width) {
				            image.height *= width / image.width;
				            image.width = width;
				        } else if (image.width >= image.height && image.height > height) {
				            image.width *= height / image.height;
				            image.height = height;
				        }
				        canvas.width = image.width > width ? width : image.width;
				        canvas.height = image.height > height ? height : image.height;
				    } else {
				        if (image.width >= image.height && image.width > width) {
				            image.height *= width / image.width;
				            image.width = width;
				        } else if (image.width <= image.height && image.height > height) {
				            image.width *= height / image.height;
				            image.height = height;
				        }
				        canvas.width = image.width;
				        canvas.height = image.height;
				    }
				    ctx.drawImage(image, 0, 0, image.width, image.height);
				    blob = file.type == "image/jpeg" ? dataURL2Blob(canvas.toDataURL("image/jpeg", 0.95)) : dataURL2Blob(canvas.toDataURL(file.type));
				}

				if (!$(element).data("images")) $(element).data("images", []);
				$(element).data("images").push({ blob: blob, name: file.name });
				completed(element, file, message);
			};
			image.src = dataUrl;
		}

		function loadImage(file, element, message, width, height, deal) {
			if (!file.type.match(/image.*/)) {
				window.alert("只能选择图片文件");
				return;
			}
			var reader = new FileReader();

			reader.onload = function (e) {
			    render(e.target.result, file, element, message, width, height, deal);
			};
			reader.readAsDataURL(file);
		}
		var width = this.attr("data-width"),
            height = this.attr("data-height"),
            deal = this.attr("data-deal");

		if (width && height) {
		    this.on("change", function () {
		        $(this).parentsUntil("body", "form").addClass("image-deal");
			    $(this).data("images", null);
			    if (start) start();
			    $(this).trigger("dealing");
				if (this.files.length == 0) {
					if (finish) finish(null);
					$(element).trigger("dealt");
					return;
				}
				var message = $app.message("图片处理中")
				for (var i = 0; i < this.files.length; i++) {
				    loadImage(this.files[i], this, message, Number(width), Number(height), deal);
				}
			});
		}
		return this;
	}
});

oldmansoft.webapp.initialled(function () {
    $(document).on("submit", "form.auto", oldmansoft.webapp.extend.form_auto_submit);
    $(document).on("click", "a[target=_script]", oldmansoft.webapp.extend.link_script_click);
	$app.option().viewLoaded(function (view) {
	    view.node.find("form.auto input[type=file][data-width][data-height]").each(function () {
			var $this = $(this);
			$this.imageDeal(function (file) {
			    if ($this.hasClass("file-input")) $this.next().text(file == null ? "" : file.name);
			}).on("dealing", function () {
			    if ($this.hasClass("file-input")) $this.next().text("处理中...");
			});
			if ($this.hasClass("file-input")) {
			    $this.next().click(function () {
			        $this.click();
			    });
			}
	    });

	    view.node.find("form").each(function () {
	        oldmansoft.webapp.extend.form_verify($(this));
	    });
	});
});<|endoftext|>


<commit_before>Ext.define('doweown.controller.Main', {
    extend: 'Ext.app.Controller',

    requires: [
	'Ext.data.proxy.JsonP',
	'Ext.navigation.View',
	'doweown.model.Isbn',
	'doweown.store.Biblio',
	'doweown.store.AvailStore',
	'doweown.store.BranchStore',
	'doweown.store.WorldCatStore'
    ],

    config: {
	views: ['doweown.view.Main', 'doweown.view.SingleBookView',
	  'doweown.view.WorldCatView'],
        refs: { 'scanBtn': 'main #scanBtn',
		'mainScreen': 'main #mainscreen'
        },
    	control: {
            scanBtn: { tap: 'scanImage' }
         }
    },

    validateBarcode: function(barcode) {
       var sum, i;

       if (barcode.length == 13) {
          barcode.replace(/[-\s]/g,'');

    	  sum = 0;
    	  for (i = 0; i < 13; i += 2) {
      	    sum += +barcode[i];
    	   }
    	  for (i = 1; i < 12; i += 2){
      		sum += 3 * +barcode[i];
    		}
    	  return sum % 10 === 0;
       }
       else if (barcode.length == 10) {
          barcode = barcode.replace(/[^\dX]/gi, '');
		  var chars = barcode.split('');
		  if(chars[9].toUpperCase() == 'X'){
  			chars[9] = 10;
  		  }
  		  sum = 0;
		  for (i = 0; i < chars.length; i++) {
		  	sum += ((10-i) * parseInt(chars[i]));
  		  }
		  return ((sum % 11) == 0);
       }
       else {
       	  return false;
       }

    },

	//get thumb and optional descriptive blurb info
	googleLookup: function(gBooksUrl, searchType) {
		var ms = this.getMainScreen();
		console.log('google lookup');
		console.log('gbooks called url: ' + gBooksUrl);
		Ext.data.JsonP.request({
        	url: gBooksUrl,
			disableCaching: true,
            success: function(res, request) {
                	// Get the gbooks data from the json object result
                console.log('google jsonp call successful');
                console.log('res.totalItems: ' + res.totalItems);
				if (res.totalItems > 0) {
					gBooksResult = true;
				  	console.log("google worked");
				  	thumb = res.items[0].volumeInfo.imageLinks.smallThumbnail
				  	if ( thumb == null ) {
				  	  thumb = 'http://books.google.com/googlebooks/images/no_cover_thumb.gif';
				  	}

				  	console.log('thumb: ' + thumb);
				 	title =  res.items[0].volumeInfo.title;
				 	console.log('title: ' + title);
	             	date =  res.items[0].volumeInfo.publishedDate;
	             	console.log('date: ' + date);
	                publisher =  res.items[0].volumeInfo.publisher;
	                console.log('publisher: ' + publisher);
	                description = res.items[0].volumeInfo.description;
	                console.log('description: ' + description);
	                //return {thumb: thumb, description: description};
	                //update thumbs
	                if (searchType=='hollis') {
	                   var hollis = Ext.getStore('Biblio');
	                   var hollisRec = hollis.getAt(0);
	                   hollisRec.set('thumb', thumb);
	                   hollisRec.set('description', description);
	                   if (hollisRec.get('title') == '' )
	                      hollisRec.set('title', title);
	                   hollis.sync();
	                   ms.push({ xtype: 'singlebook' });
	                }
	                else {
	                   var worldCat = Ext.getStore('WorldCatStore');
	                   var worldCatRec = worldCatStore.getAt(0);
	                   worldCatRec.set('thumbnail', thumb);
	                   worldCatRec.set('description', description);
	                   worldCat.sync();
	                   ms.push({ xtype : 'worldcatview' });
	                }

				}
				else { // not found in gbooks, do worldcat lookup
						//do worldcat lookup
						console.log('thumbnail not found in gbooks');
						if (searchType=='hollis')
	                   		ms.push({ xtype: 'singlebook' });
	                	else
	                   		ms.push({ xtype : 'worldcatview' });
				}
		    },
			failure: function(res, request) { //gBooks lookup req failed - try worldcat anyway
					console.log("gbooks thumbnail lookup call failed");
					if (searchType=='hollis')
	                   	ms.push({ xtype: 'singlebook' });
	                else
	                   ms.push({ xtype : 'worldcatview' });
			}
		});

	},

    worldCatLookup: function(barcode) {
  	console.log('commencing worldcat lookup for isbn: ' + barcode);
  	var ms = this.getMainScreen();
  	var mainController = this;
	var worldCatURL = doweown.config.Config.getWorldCatUrl();
	var gBooksURL = doweown.config.Config.getGoogleBooksUrl();

	var lookupURL = worldCatURL + barcode;
	console.log('worldcat url is: ' + lookupURL);
	var worldCatStore = Ext.getStore('WorldCatStore');
	if (worldCatStore.getAllCount() > 0) {
        worldCatStore.removeAll();
    }
	Ext.data.JsonP.request({
	    url: lookupURL,
	    disableCaching: true,
	    callbackKey: 'callback',
	    params: {
        	wskey: doweown.config.Config.getWorldCatDevKey(),
            oclcsymbol:  doweown.config.Config.getWorldCatLibs(),
            format: 'json'
        },
	    success: function(res, request) {
	        if (typeof res.title != 'undefined'){
	          console.log('worldcat jsonp call successful');
	          var title = res.title;
	          console.log('title: ' + title);
	          var author = res.author;
	          var date = res.date;
	          var publisher = res.publisher;
	          var ISBN = res.ISBN;
	          var totalLibCount = res.totalLibCount;
	          var library = res.library;
	          console.log('libraries: ' + library);
	          var worldCatRec = Ext.create('doweown.model.WorldCatBooks', {
	            'title': title,
	            'author': author,
	            'date': date,
	            'publisher': publisher,
	            'ISBN': ISBN,
	            'library': library
	          });
	          console.log('worldcat record created');
	          worldCatStore.add(worldCatRec);
	          console.log('worldcat record added');
	        //worldCatStore.sync();
	        //console.log('worldcat store synced');
	          console.log("worldcat store loaded with " +
	           worldCatStore.getAllCount() + " records");
	          //lookup google for thumbnail & go to worldcat result list
	          var isbnString = '';
              for (var i=0; i < ISBN.length; i++) {
			  	isbnString = isbnString + 'isbn:' + ISBN[i];
                if (i < (isbnList.length-2))
                	isbnString = isbnString + '+OR+';
               }
              console.log('isbnString: ' + isbnString);
              gBooksURL = gBooksURL + isbnString;
              console.log('gbooks url: ' + gBooksURL);
	          mainController.googleLookup(gBooksURL,'worldcat');
	          //ms.push({ xtype : 'worldcatview' });
	        }
	        else { //not in worldcat
	        	Ext.Msg.alert("Catalog info for ISBN " + barcode + " not found.");
	        }
	    },
	    failure: function(res, request) { //worldcat lookup  failed - goto email form
	    	Ext.Msg.alert("Catalog info for ISBN " + barcode + " not found.");
	    }

	});

    },

     hollisLookup: function(barcode) {
		//presto search goes here
		var mainController = this;
		var gBooksURL = doweown.config.Config.getGoogleBooksUrl(); // + 'isbn:' + barcode;
		console.log('commencing hollis lookup');
		var ms = this.getMainScreen();
		var availURL;
		var isbnURL = doweown.config.Config.getHollisIsbnUrl() + barcode;
		var similarURL = doweown.config.Config.getHollisSimilarUrl();

		var gBooksResult = false;
		var availResult = false;
		var isbnResult = false;
		var similarResult = false;

		var title = '';
		var publisher = '';
		var place = '';
		var description = '';
		var author = '';
		var thumb = '';
		var date = '';
		var hollisId = 0;
		console.log('hollis url: ' + isbnURL);

		var gBooksStore = Ext.getStore('GbooksStore');
	    if (gBooksStore.getAllCount() > 0) {
        		gBooksStore.removeAll();
         }

		//new direct hollis call
		Ext.data.JsonP.request({
                       url: isbnURL,
                       callbackKey: 'jsonp',
                       disableCaching: true,
                       success: function(res, request) {
			           console.log("hollis lookup");
                         // Get the isbn data from the json object result
                         if (res.mods) {
                          isbnResult = true;
                          console.log("isbn worked");
                          //console.log('gbooks url: ' + gBooksURL);

                          var isbnString = '';
                          var isbnList = res.mods.identifier;
                          if (isbnList instanceof Array) {
                            for (var i=0; i < isbnList.length; i++) {
                          	  if (res.mods.identifier[i].type == 'isbn') {
                          	      var l = res.mods.identifier[i].content;
                          	      if (typeof l == 'string' || l instanceof String){
                          	          l = l.split(' ',1);
                          	       }
                          		  isbnString = isbnString + 'isbn:' + l;
                          		  if (i < (isbnList.length-2)) {
                          		     isbnString = isbnString + '+OR+';
                          		  }
                          	  }
                            }
                          } else {
                            isbnString = 'isbn:' + res.mods.identifier.content.split(' ',1);
                          }
                          console.log('isbnString: ' + isbnString);
                          gBooksURL = gBooksURL + isbnString;
                          //call google
	                      console.log('gbooks url: ' + gBooksURL);

                          hollisId = res.mods.recordInfo.recordIdentifier.substring(0,9);
                          console.log('hollis id is: ' + hollisId);

                          if (res.mods.titleInfo.title instanceof String)
                          	title = res.mods.titleInfo.title;
                          else if (res.mods.titleInfo instanceof Array)
                          	title = res.mods.titleInfo[0].title;
                          else
                          	title = '';
                          if (res.mods.titleInfo.nonSort)
                             title = res.mods.titleInfo.nonSort + ' ' +title;
                          if (res.mods.titleInfo.subTitle)
                             title = title + ': ' + res.mods.titleInfo.subTitle;
                          console.log('hollis title: ' + title);
                          author = res.mods.name.namePart;
                          console.log('hollis author: ' + author);
                          place = res.mods.originInfo.place[1].placeTerm.content;
                          console.log('hollis place: ' + place);
                          publisher = res.mods.originInfo.publisher;
                          console.log('hollis pub: ' + publisher);
                          if (res.mods.originInfo.dateIssued.content)
                             date = res.mods.originInfo.dateIssued.content;
                          else
                             date = res.mods.originInfo.dateIssued;
                          console.log('hollis date: ' + date);

						  //call presto again for availabilty
						  availURL  = doweown.config.Config.getHollisAvailUrl() +hollisId;
                          console.log(availURL);
                          Ext.data.JsonP.request({
                     	      url: availURL,
                              callbackKey: 'jsonp',
                              disableCaching: true,
                              success: function(res, request) {
                                // Get the availability data from the json object result
                                if (res.availability) {
                                  availResult = true;
                                  console.log("avail worked");
                                  //console.log(availResult);
								  //add book to books store and availability store
						          var hollisRec = Ext.create('doweown.model.Isbn', {
						             'title' :   title,
						             'author':   author,
						             'date':     date,
						             'place':    place,
						             'publisher': publisher,
						             'hollisId': hollisId
						          });
						          var Biblio = Ext.getStore('Biblio');

						          if (Biblio.getAllCount() > 0) {
						              Biblio.removeAll();
						          }
								  Biblio.add(hollisRec);
								  var BranchStore = Ext.getStore('BranchStore');
								  if (BranchStore.getAllCount() > 0) {
                                      BranchStore.removeAll();
                                  }
								  BranchStore.getProxy().setUrl(availURL);
                                  BranchStore.load();
								  BranchStore.sync();
                               	  // lookup google for thumbnail & switch to result view
                               	  mainController.googleLookup(gBooksURL,'hollis');
								  //ms.push({ xtype : 'singlebook' });
                                }
                              }
                          });
                	    }
            		   },
					   failure: function(res, request) { //not in hollis
			   			 //do worldcat lookup
			   			 //Ext.Msg.alert(barcode + " not in hollis. sorry.");
			   			 console.log(barcode + " not in hollis. sorry.");
			   			 mainController.worldCatLookup(barcode);
					   }
        			});

     }, //end hollis

    scanImage: function() {
	  var scanner = cordova.require("cordova/plugin/BarcodeScanner");
	  mainController = this;

        scanner.scan(
        	function(result) {
        	   var barcode = result.text;
               if (result.text)
			    {
			    	if (mainController.validateBarcode(barcode)) {
			    		console.log("valid barcode");
                		mainController.hollisLookup(barcode);
                	}
                	else {
                		Ext.Msg.alert("Invalid barcode " + barcode);
                	}
                }
            },
            function(error) {
               Ext.Msg.alert("Whoops! Scanning failed: " + error);
            }
		);
    }

});
<commit_msg>fixed worldcat issues, grabbed more data from google lookup for hollis view<commit_after>Ext.define('doweown.controller.Main', {
    extend: 'Ext.app.Controller',

    requires: [
	'Ext.data.proxy.JsonP',
	'Ext.navigation.View',
	'doweown.model.Isbn',
	'doweown.store.Biblio',
	'doweown.store.AvailStore',
	'doweown.store.BranchStore',
	'doweown.store.WorldCatStore'
    ],

    config: {
	views: ['doweown.view.Main', 'doweown.view.SingleBookView',
	  'doweown.view.WorldCatView'],
        refs: { 'scanBtn': 'main #scanBtn',
		'mainScreen': 'main #mainscreen'
        },
    	control: {
            scanBtn: { tap: 'scanImage' }
         }
    },

    validateBarcode: function(barcode) {
       var sum, i;

       if (barcode.length == 13) {
          barcode.replace(/[-\s]/g,'');

    	  sum = 0;
    	  for (i = 0; i < 13; i += 2) {
      	    sum += +barcode[i];
    	   }
    	  for (i = 1; i < 12; i += 2){
      		sum += 3 * +barcode[i];
    		}
    	  return sum % 10 === 0;
       }
       else if (barcode.length == 10) {
          barcode = barcode.replace(/[^\dX]/gi, '');
		  var chars = barcode.split('');
		  if(chars[9].toUpperCase() == 'X'){
  			chars[9] = 10;
  		  }
  		  sum = 0;
		  for (i = 0; i < chars.length; i++) {
		  	sum += ((10-i) * parseInt(chars[i]));
  		  }
		  return ((sum % 11) == 0);
       }
       else {
       	  return false;
       }

    },

	//get thumb and optional descriptive blurb info
	googleLookup: function(gBooksUrl, searchType) {
		var ms = this.getMainScreen();
		var title,thumb,description,date,author,publisher;
		console.log('google lookup');
		console.log('gbooks called url: ' + gBooksUrl);
		Ext.data.JsonP.request({
        	url: gBooksUrl,
			disableCaching: true,
            success: function(res, request) {
                	// Get the gbooks data from the json object result
                console.log('google jsonp call successful');
                console.log('res.totalItems: ' + res.totalItems);
				if (res.totalItems > 0) {
					gBooksResult = true;
				  	console.log("google worked");
				  	thumb = res.items[0].volumeInfo.imageLinks.smallThumbnail
				  	if ( thumb == null ) {
				  	  thumb = 'http://books.google.com/googlebooks/images/no_cover_thumb.gif';
				  	}

				  	console.log('thumb: ' + thumb);
				 	title =  res.items[0].volumeInfo.title;
				 	console.log('title: ' + title);
				 	//author =  res.items[0].volumeInfo.author;
				 	//console.log('author: ' + author);
	             	date =  res.items[0].volumeInfo.publishedDate;
	             	console.log('date: ' + date);
	                publisher =  res.items[0].volumeInfo.publisher;
	                console.log('publisher: ' + publisher);
	                description = res.items[0].volumeInfo.description;
	                console.log('description: ' + description);
	                //return {thumb: thumb, description: description};
	                //update thumbs
	                if (searchType=='hollis') {
	                   var hollis = Ext.getStore('Biblio');
	                   var hollisRec = hollis.getAt(0);
	                   hollisRec.set('thumb', thumb);
	                   hollisRec.set('description', description);
	                   hollisRec.set('date', date);
	                   if (hollisRec.get('title') == '' )
	                      hollisRec.set('title', title);
	                   //if (hollisRec.get('author') == '' )
	                   //   hollisRec.set('author', author);
	                   //hollis.sync();
	                   console.log('showing singlebookview');
	                   ms.push({ xtype: 'singlebook' });
	                }
	                else {
	                   var worldCat = Ext.getStore('WorldCatStore');
	                   console.log("worldcat store loaded with " + worldCat.getAllCount() + " records");
	                   var worldCatRec = worldCat.getAt(0);
	                   console.log("updating world cat record: " + worldCatRec.get('title') );
	                   worldCatRec.set('thumbnail', thumb);
	                   worldCatRec.set('description', description);
	                   console.log('showing worldcatview');
	                   ms.push({ xtype : 'worldcatview' });
	                }

				}
				else { // not found in gbooks, do worldcat lookup
						//do worldcat lookup
						console.log('thumbnail not found in gbooks');
						if (searchType=='hollis')
	                   		ms.push({ xtype: 'singlebook' });
	                	else
	                   		ms.push({ xtype : 'worldcatview' });
				}
		    },
			failure: function(res, request) { //gBooks lookup req failed - try worldcat anyway
					console.log("gbooks thumbnail lookup call failed");
					if (searchType=='hollis')
	                   	ms.push({ xtype: 'singlebook' });
	                else
	                   ms.push({ xtype : 'worldcatview' });
			}
		});

	},

    worldCatLookup: function(barcode) {
  	console.log('commencing worldcat lookup for isbn: ' + barcode);
  	var ms = this.getMainScreen();
  	var mainController = this;
	var worldCatURL = doweown.config.Config.getWorldCatUrl();
	var gBooksURL = doweown.config.Config.getGoogleBooksUrl();

	var lookupURL = worldCatURL + barcode;
	console.log('worldcat url is: ' + lookupURL);
	var worldCatStore = Ext.getStore('WorldCatStore');
	if (worldCatStore.getAllCount() > 0) {
        worldCatStore.removeAll();
    }
	Ext.data.JsonP.request({
	    url: lookupURL,
	    disableCaching: true,
	    callbackKey: 'callback',
	    params: {
        	wskey: doweown.config.Config.getWorldCatDevKey(),
            oclcsymbol:  doweown.config.Config.getWorldCatLibs(),
            format: 'json'
        },
	    success: function(res, request) {
	        if (typeof res.title != 'undefined'){
	          console.log('worldcat jsonp call successful');
	          var title = res.title;
	          console.log('title: ' + title);
	          var author = res.author;
	          var date = res.date;
	          var publisher = res.publisher;
	          var ISBN = res.ISBN;
	          var totalLibCount = res.totalLibCount;
	          var library = res.library;
	          console.log('libraries: ' + library);
	          var worldCatRec = Ext.create('doweown.model.WorldCatBooks', {
	            'title': title,
	            'author': author,
	            'date': date,
	            'publisher': publisher,
	            'ISBN': ISBN,
	            'library': library
	          });
	          console.log('worldcat record created');
	          worldCatStore.add(worldCatRec);
	          //worldCatStore.sync();
	          console.log('worldcat record added');
	        //worldCatStore.sync();
	        //console.log('worldcat store synced');
	          console.log("worldcat store loaded with " +
	           worldCatStore.getAllCount() + " records");
	          //lookup google for thumbnail & go to worldcat result list
	          var isbnString = '';
	          if (ISBN instanceof Array ) {
                for (var i=0; i < ISBN.length; i++) {
			  	  isbnString = isbnString + 'isbn:' + ISBN[i];
                  if (i < (ISBN.length-1))
                	  isbnString = isbnString + '+OR+';
                 }
              }
              else { // instance of String
                isbnString = "isbn:" + ISBN;
              }
              console.log('isbnString: ' + isbnString);
              gBooksURL = gBooksURL + isbnString;
              console.log('gbooks url: ' + gBooksURL);
	          mainController.googleLookup(gBooksURL,'worldcat');
	          //ms.push({ xtype : 'worldcatview' });
	        }
	        else { //not in worldcat
	        	Ext.Msg.alert("Catalog info for ISBN " + barcode + " not found.");
	        }
	    },
	    failure: function(res, request) { //worldcat lookup  failed - goto email form
	    	Ext.Msg.alert("Catalog info for ISBN " + barcode + " not found.");
	    }

	});

    },

     hollisLookup: function(barcode) {
		//presto search goes here
		var mainController = this;
		var gBooksURL = doweown.config.Config.getGoogleBooksUrl(); // + 'isbn:' + barcode;
		console.log('commencing hollis lookup');
		var ms = this.getMainScreen();
		var availURL;
		var isbnURL = doweown.config.Config.getHollisIsbnUrl() + barcode;
		var similarURL = doweown.config.Config.getHollisSimilarUrl();

		var gBooksResult = false;
		var availResult = false;
		var isbnResult = false;
		var similarResult = false;

		var title = '';
		var publisher = '';
		var place = '';
		var description = '';
		var author = '';
		var thumb = '';
		var date = '';
		var hollisId = 0;
		console.log('hollis url: ' + isbnURL);

		var gBooksStore = Ext.getStore('GbooksStore');
	    if (gBooksStore.getAllCount() > 0) {
        		gBooksStore.removeAll();
         }

		//new direct hollis call
		Ext.data.JsonP.request({
                       url: isbnURL,
                       callbackKey: 'jsonp',
                       disableCaching: true,
                       success: function(res, request) {
			           console.log("hollis lookup");
                         // Get the isbn data from the json object result
                         if (res.mods) {
                          isbnResult = true;
                          console.log("isbn worked");
                          //console.log('gbooks url: ' + gBooksURL);

                          var isbnString = '';
                          var isbnList = res.mods.identifier;
                          if (isbnList instanceof Array) {
                            for (var i=0; i < isbnList.length; i++) {
                          	  if (res.mods.identifier[i].type == 'isbn') {
                          	      var l = res.mods.identifier[i].content;
                          	      if (typeof l == 'string' || l instanceof String){
                          	          l = l.split(' ',1);
                          	       }
                          		  isbnString = isbnString + 'isbn:' + l;
                          		  if (i < (isbnList.length-2)) {
                          		     isbnString = isbnString + '+OR+';
                          		  }
                          	  }
                            }
                          } else { //single isbn
                            if (res.mods.identifier.content instanceof String)
                              isbnString = 'isbn:' + res.mods.identifier.content.split(' ',1);
                            else
                              isbnString = 'isbn:' + res.mods.identifier.content;
                          }
                          // append the original isbn barcode found in the gbooks url if
                          // not in the hollis record, since its not always there. good grief
                          if (isbnString.indexOf(barcode) == -1)
                          	isbnString = isbnString + '+OR+isbn:' + barcode;
                          if (isbnString.length == 0)
                             isbnString = 'isbn:' + barcode;
                          console.log('isbnString: ' + isbnString);
                          gBooksURL = gBooksURL + isbnString;
                          //call google
	                      console.log('gbooks url: ' + gBooksURL);

                          hollisId = res.mods.recordInfo.recordIdentifier.substring(0,9);
                          console.log('hollis id is: ' + hollisId);

                          if (res.mods.titleInfo.title instanceof String)
                          	title = res.mods.titleInfo.title;
                          else if (res.mods.titleInfo instanceof Array)
                          	title = res.mods.titleInfo[0].title;
                          else
                          	title = '';
                          if (res.mods.titleInfo.nonSort)
                             title = res.mods.titleInfo.nonSort + ' ' +title;
                          if (res.mods.titleInfo.subTitle)
                             title = title + ': ' + res.mods.titleInfo.subTitle;
                          console.log('hollis title: ' + title);
                          author = res.mods.name.namePart;
                          console.log('hollis author: ' + author);
                          place = res.mods.originInfo.place[1].placeTerm.content;
                          console.log('hollis place: ' + place);
                          publisher = res.mods.originInfo.publisher;
                          console.log('hollis pub: ' + publisher);
                          if (res.mods.originInfo.dateIssued.content)
                             date = res.mods.originInfo.dateIssued.content;
                          else
                             date = res.mods.originInfo.dateIssued;
                          console.log('hollis date: ' + date);

						  //call presto again for availabilty
						  availURL  = doweown.config.Config.getHollisAvailUrl() +hollisId;
                          console.log(availURL);
                          Ext.data.JsonP.request({
                     	      url: availURL,
                              callbackKey: 'jsonp',
                              disableCaching: true,
                              success: function(res, request) {
                                // Get the availability data from the json object result
                                if (res.availability) {
                                  availResult = true;
                                  console.log("avail worked");
                                  //console.log(availResult);
								  //add book to books store and availability store
						          var hollisRec = Ext.create('doweown.model.Isbn', {
						             'title' :   title,
						             'author':   author,
						             'date':     date,
						             'place':    place,
						             'publisher': publisher,
						             'hollisId': hollisId
						          });
						          var Biblio = Ext.getStore('Biblio');

						          if (Biblio.getAllCount() > 0) {
						              Biblio.removeAll();
						          }
								  Biblio.add(hollisRec);
								  var BranchStore = Ext.getStore('BranchStore');
								  if (BranchStore.getAllCount() > 0) {
                                      BranchStore.removeAll();
                                  }
								  BranchStore.getProxy().setUrl(availURL);
                                  BranchStore.load();
								  BranchStore.sync();
                               	  // lookup google for thumbnail & switch to result view
                               	  mainController.googleLookup(gBooksURL,'hollis');
								  //ms.push({ xtype : 'singlebook' });
                                }
                              }
                          });
                	    }
            		   },
					   failure: function(res, request) { //not in hollis
			   			 //do worldcat lookup
			   			 //Ext.Msg.alert(barcode + " not in hollis. sorry.");
			   			 console.log(barcode + " not in hollis. sorry.");
			   			 mainController.worldCatLookup(barcode);
					   }
        			});

     }, //end hollis

    scanImage: function() {
	  var scanner = cordova.require("cordova/plugin/BarcodeScanner");
	  mainController = this;

        scanner.scan(
        	function(result) {
        	   var barcode = result.text;
               if (result.text)
			    {
			    	if (mainController.validateBarcode(barcode)) {
			    		console.log("valid barcode");
                		mainController.hollisLookup(barcode);
                	}
                	else {
                		Ext.Msg.alert("Invalid barcode " + barcode);
                	}
                }
            },
            function(error) {
               Ext.Msg.alert("Whoops! Scanning failed: " + error);
            }
		);
    }

});
<|endoftext|>