Advertisement
erupnu

Enyo 1.0 Textarea Kind

Feb 4th, 2012
317
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. enyo.kind({
  3.     name: "Textarea",
  4.     kind: enyo.Control,
  5.     published: {
  6.         hint: enyo._$L("Tap Here To Type"),
  7.         value: "",
  8.         tabIndex: "",
  9.         // HTML5 'spellcheck' attribute
  10.         spellcheck: true,
  11.         // maps to Mobile Safari 'autocorrect' attribute
  12.         autocorrect: true,
  13.         //* Possible settings: "num-lock", "caps-lock", "shift-lock", "shift-single", "num-single",
  14.         autoKeyModifier: "",
  15.         //* Possible settings: "sentence", "title", "lowercase" (actual attribute is cap +)
  16.         autoCapitalize: "sentence",
  17.         //* Set to true to enable auto-emoticons support
  18.         autoEmoticons: false,
  19.         //* Set to true to enable auto-linking support
  20.         autoLinking: false,
  21.         //* Set to false to disable automatic word completion
  22.         autoWordComplete: true,
  23.         //* Specifies the 'type' attribute on the input field.  On webOS, this modifies the virtual keyboard layout, supported values are "email" and "url".
  24.         inputType: "",
  25.         //* css class to apply to the inner input control
  26.         inputClassName: "",
  27.         //* css class to apply on focus
  28.         focusClassName: "enyo-input-focus",
  29.         //* css class to apply inner controls to control spacing
  30.         spacingClassName: "enyo-input-spacing",
  31.         //* Set to true to make the input look focused when it's not.
  32.         alwaysLooksFocused: false,
  33.         /**
  34.         The selection property is an object describing selected text. The start and end properties
  35.         specify the zero-based starting and ending indexes of the selection.
  36.         For example, if an input value is "Value"
  37.         and getSelection returns {start: 1, end: 3} then "al" is selected. To select "alu," call:
  38.  
  39.             this.$.input.setSelection({start: 1, end: 4});
  40.         */
  41.         selection: null,
  42.         disabled: false,
  43.         /**
  44.         Set to true to fire the onchange event as well as the oninput event
  45.         whenever the input content is changed.
  46.         */
  47.         changeOnInput: false,
  48.         /**
  49.         Set to the number of milliseconds to delay the input event when a key is pressed.
  50.         If another key is pressed within the delay interval, the input will be postponed
  51.         and fired once only after the delay has elapsed without a key being pressed.
  52.         */
  53.         keypressInputDelay: 0,
  54.         //* Set to false to avoid any default styling from being applied
  55.         styled: true,
  56.         //* Set to true to select all text when the input gains focus
  57.         selectAllOnFocus: false
  58.     },
  59.     events: {
  60.         onfocus: "",
  61.         onblur: "",
  62.         onchange: "",
  63.         oninput: "",
  64.         onmousedown: "",
  65.         onmouseup: "",
  66.         //* The onkeypress event can be used to filter out disallowed characters.
  67.         onkeypress: ""
  68.     },
  69.     className: "enyo-input",
  70.     //* @protected
  71.     chrome: [
  72.         {name: "input", flex: 1, kind: "BasicTextarea", className: "enyo-input-input"}
  73.     ],
  74.     clientChrome: [
  75.         {name: "client", kind: "HFlexBox", align: "center"}
  76.     ],
  77.     create: function() {
  78.         this.inherited(arguments);
  79.         this.updateSpacingControl();
  80.         this.disabledChanged();
  81.         this.inputTypeChanged();
  82.         this.tabIndexChanged();
  83.         this.valueChanged();
  84.         this.hintChanged();
  85.         this.alwaysLooksFocusedChanged();
  86.         this.inputClassNameChanged();
  87.         this.styledChanged();
  88.         this.applySmartTextOptions();
  89.     },
  90.     destroy: function() {
  91.         this.stopInputDelayJob();
  92.         this.inherited(arguments);
  93.     },
  94.     addControl: function(inControl) {
  95.         if (!inControl.isChrome && !this.$.client) {
  96.             this.createChrome(this.clientChrome);
  97.             this.$.input.setParent(this.$.client);
  98.             this.updateSpacingControl();
  99.         }
  100.         this.inherited(arguments);
  101.     },
  102.     selectAllHandler: function() {
  103.         document.execCommand("selectAll");
  104.     },
  105.     cutHandler: function() {
  106.         document.execCommand("cut");
  107.     },
  108.     copyHandler: function() {
  109.         document.execCommand("copy");
  110.     },
  111.     pasteHandler: function() {
  112.         if (PalmSystem && PalmSystem.paste) {
  113.             PalmSystem.paste();
  114.         }
  115.     },
  116.     mousedownHandler: function(inSender, inEvent) {
  117.         var r = this.doMousedown(inEvent);
  118.         this.chromeMousedown = (inEvent.dispatchTarget != this.$.input) ? inEvent : null;
  119.         if (this.chromeMousedown) {
  120.             this.handleChromeMousedown(inEvent);
  121.         }
  122.         return r;
  123.     },
  124.     handleChromeMousedown: function(inEvent) {
  125.         // FIXME: when clicking chrome, always prevent default so that chrome can never be focused.
  126.         // Do this to prevent virtual keyboard from toggling briefly (because focusAtPoint api is asynchronous).
  127.         // Because of this track cancelling of the mousedown chrome event specially.
  128.         inEvent.chromeEventPrevented = inEvent.prevented;
  129.         inEvent.preventDefault();
  130.         inEvent.preventDefault = function() {
  131.             inEvent.chromeEventPrevented = true;
  132.         }
  133.     },
  134.     focusHandler: function(inSender, inEvent) {
  135.         if (this.styled && !this.alwaysLooksFocused) {
  136.             this.addClass(this.focusClassName);
  137.         }
  138.         if (this.selectAllOnFocus) {
  139.             this.forceSelect();
  140.         }
  141.         return this.doFocus(inEvent);
  142.     },
  143.     mouseupHandler: function(inSender, inEvent) {
  144.         // force input to be focused when: there's a mousedown on chrome that's not cancelled,
  145.         // there's been no drag, and not disabled
  146.         if (this.chromeMousedown && !this.disabled && !inEvent.didDrag
  147.             && !this.chromeMousedown.chromeEventPrevented) {
  148.             this.forceFocus(null, true);
  149.         }
  150.         return this.doMouseup(inEvent);
  151.     },
  152.     blurHandler: function(inSender, inEvent) {
  153.         if (!this.alwaysLooksFocused) {
  154.             this.removeClass(this.focusClassName);
  155.         }
  156.         if (this.selectAllOnFocus) {
  157.             document.execCommand("Unselect");
  158.         }
  159.         return this.doBlur(inEvent);
  160.     },
  161.     clickHandler: function(inSender, inEvent) {
  162.         // note: follow webkit behavior to not send clicks on input elements
  163.         // this is done automatically for the input node; enforcing here to catch
  164.         // any chrome around the input.
  165.         return this.disabled ? true : this.doClick(inEvent);
  166.     },
  167.     rendered: function() {
  168.         this.inherited(arguments);
  169.         this.selectionChanged();
  170.     },
  171.     inputClassNameChanged: function() {
  172.         this.$.input.addClass(this.inputClassName);
  173.     },
  174.     alwaysLooksFocusedChanged: function() {
  175.         if (this.alwaysLooksFocused && this.styled) {
  176.             this.addClass(this.focusClassName);
  177.         }
  178.     },
  179.     inputTypeChanged: function() {
  180.         this.$.input.domAttributes.type = this.inputType;
  181.         if (this.hasNode()) {
  182.             this.$.input.render();
  183.         }
  184.     },
  185.     valueChanged: function() {
  186.         this.$.input.setValue(this.value);
  187.     },
  188.     getDomValue: function() {
  189.         return this.$.input.getDomValue();
  190.     },
  191.     getValue: function() {
  192.         return this.$.input.getValue();
  193.     },
  194.     tabIndexChanged: function() {
  195.         this.$.input.setTabIndex(this.tabIndex);
  196.     },
  197.     // dom event handler
  198.     changeHandler: function(inSender, e) {
  199.         if (!this.changeOnInput) {
  200.             this.value = inSender.getValue();
  201.             this.doChange(e, this.value);
  202.         }
  203.         return true;
  204.     },
  205.     inputHandler: function(inSender, e) {
  206.         this.value = inSender.getValue();
  207.         if (this.keypressInputDelay) {
  208.             var fn = enyo.bind(this, "processInputEvent", e);
  209.             enyo.job(this.id + "-inputDelay", fn, Number(this.keypressInputDelay));
  210.         } else {
  211.             this.processInputEvent(e);
  212.         }
  213.         return true;
  214.     },
  215.     processInputEvent: function(e) {
  216.         this.doInput(e, this.value);
  217.         if (this.changeOnInput) {
  218.             this.doChange(e, this.value);
  219.         }
  220.     },
  221.     keypressInputDelayChanged: function() {
  222.         this.stopInputDelayJob();
  223.     },
  224.     stopInputDelayJob: function() {
  225.         enyo.job.stop(this.id + "-inputDelay");
  226.     },
  227.     selectionChanged: function() {
  228.         var n = this.$.input.hasNode();
  229.         if (n && this.selection) {
  230.             n.selectionStart = this.selection.start;
  231.             n.selectionEnd = this.selection.end;
  232.         }
  233.     },
  234.     getSelection: function() {
  235.         var n = this.$.input.hasNode();
  236.         return n ? {start: n.selectionStart, end: n.selectionEnd} : {start: 0, end: 0};
  237.     },
  238.     disabledChanged: function() {
  239.         this.$.input.setDisabled(this.disabled);
  240.     },
  241.     hintChanged: function() {
  242.         this.$.input.setPlaceholder(this.hint);
  243.     },
  244.     // FIXME: Smart text replace options (could be factored out)
  245.     autoKeyModifierChanged: function() {
  246.         this.$.input.setAttribute("x-palm-text-entry", this.autoKeyModifier ? this.autoKeyModifier : null);
  247.     },
  248.     autoCapitalizeChanged: function() {
  249.         if (this.autoCapitalize === "lowercase") {
  250.             this.$.input.setAttribute("x-palm-disable-auto-cap", "true");
  251.             this.$.input.setAttribute("x-palm-title-cap", null);
  252.         } else {
  253.             this.$.input.setAttribute("x-palm-disable-auto-cap", null);
  254.             this.$.input.setAttribute("x-palm-title-cap", (this.autoCapitalize === "title") ? true : null);
  255.         }
  256.     },
  257.     autocorrectChanged: function() {
  258.         // FIXME: our WebKit implementation of 'autocorrect' and 'spellcheck' doesn't work for all 4 possible values
  259.         this.$.input.setAttribute("autocorrect", this.autocorrect ? "on" : "off");
  260.     },
  261.     spellcheckChanged: function() {
  262.         // FIXME: our WebKit implementation of 'autocorrect' and 'spellcheck' doesn't work for all 4 possible values
  263.         this.$.input.setAttribute("spellcheck", !!this.spellcheck);
  264.     },
  265.  
  266.     autoLinkingChanged: function() {
  267.         this.$.input.setAttribute("x-palm-enable-linker", this.autoLinking ? this.autoLinking : null);
  268.     },
  269.     autoEmoticonsChanged: function() {
  270.         this.$.input.setAttribute("x-palm-enable-emoticons", this.autoEmoticons ? this.autoEmoticons : null);
  271.     },
  272.     autoWordCompleteChanged: function() {
  273.         this.$.input.setAttribute("x-palm-word-completions", this.autoWordComplete ? null : "disabled");
  274.     },
  275.     applySmartTextOptions: function() {
  276.         this.spellcheckChanged();
  277.         this.autoWordCompleteChanged();
  278.         this.autocorrectChanged();
  279.         this.autoLinkingChanged();
  280.         this.autoEmoticonsChanged();
  281.         this.autoCapitalizeChanged();
  282.         this.autoKeyModifierChanged();
  283.     },
  284.     // control used to reclaim space, can be either input or client
  285.     updateSpacingControl: function() {
  286.         var c = this.$.client || this.$.input;
  287.         if (c != this.spacingControl) {
  288.             if (this.spacingControl) {
  289.                 this.spacingControl.removeClass(this.spacingClassName);
  290.             }
  291.             this.spacingControl = c;
  292.         }
  293.         this.spacingClassNameChanged();
  294.     },
  295.     spacingClassNameChanged: function(inOldValue) {
  296.         if (this.spacingControl) {
  297.             if (inOldValue) {
  298.                 this.spacingControl.removeClass(inOldValue);
  299.             }
  300.             this.spacingControl.addClass(this.spacingClassName);
  301.         }
  302.     },
  303.     styledChanged: function(inOldValue) {
  304.         this.addRemoveClass(this.ctor.prototype.className, this.styled);
  305.         if (this.spacingControl) {
  306.             this.spacingControl.addRemoveClass(this.spacingClassName, this.styled);
  307.         }
  308.     },
  309.     //* @public
  310.     isEmpty: function() {
  311.         return this.$.input.isEmpty();
  312.     },
  313.     /**
  314.         Forces this input to be focused.
  315.     */
  316.     forceFocus: function(inCallback, inSync) {
  317.         this.$.input.forceFocus(inCallback, inSync);
  318.     },
  319.     /**
  320.         Force this input to be focused and set the keyboard to automatic mode.
  321.     */
  322.     forceFocusEnableKeyboard: function() {
  323.         this.forceFocus(enyo.bind(enyo, enyo.keyboard.setManualMode, false));
  324.     },
  325.     /**
  326.         Forces this input to be blurred (lose focus).
  327.     */
  328.     forceBlur: function(inCallback, inSync) {
  329.         this.$.input.forceBlur(inCallback, inSync);
  330.     },
  331.     /**
  332.         Force select all text in this input.
  333.     */
  334.     forceSelect: function(inCallback, inSync) {
  335.         this.$.input.forceSelect(inCallback, inSync);
  336.     },
  337.     /**
  338.         Returns true if the input has keyboard focus.
  339.     */
  340.     hasFocus: function() {
  341.         return this.$.input.hasFocus();
  342.     }
  343. });
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351. enyo.kind({
  352.     name: "BasicTextarea",
  353.     kind: enyo.Control,
  354.     published: {
  355.         value: "",
  356.         disabled: false,
  357.         readonly: false,
  358.         placeholder: "",
  359.         placeholderClassName: "",
  360.         disabledClassName: "enyo-input-disabled",
  361.         tabIndex: ""
  362.     },
  363.     events: {
  364.         onfocus: "",
  365.         onblur: "",
  366.         onchange: "",
  367.         onkeypress: "",
  368.         onkeyup: ""
  369.     },
  370.     //* @protected
  371.     nodeTag: "textarea",
  372.     style: "font-family: Prelude, Prelude Medium, Segoe UI, Arial, Helvetica, Sans-Serif;", //--> Added this so we do not have to modify the textarea base css class
  373.     // NOTE: only required in browser, overridden below
  374.     requiresDomMousedown: true,
  375.     create: function() {
  376.         this.inherited(arguments);
  377.        
  378.         //==========================================================
  379.         //--> For sizing:
  380.         //      min-height - is obeyed
  381.         //      height     - is transformed into min-height since this is a multi-line textbox and will grow in height, silly!
  382.         //==========================================================
  383.         if(this.parent.domStyles["min-height"]){
  384.             this.applyStyle("min-height", this.parent.domStyles["min-height"]);
  385.         }else if (this.parent.domStyles["height"]){
  386.             this.applyStyle("min-height", this.parent.domStyles["height"]);
  387.             this.parent.applyStyle("height", "");
  388.         }
  389.         if (window.PalmSystem) {
  390.             this.requiresDomMousedown = true;
  391.         }
  392.         //==========================================================
  393.        
  394.         this.placeholder = this.placeholder || this.hint || "";
  395.         enyo.mixin(this.domAttributes, {
  396.             onfocus: enyo.bubbler,
  397.             onblur: enyo.bubbler
  398.         });
  399.         this.disabledChanged();
  400.         this.readonlyChanged();
  401.         this.valueChanged();
  402.         this.placeholderChanged();
  403.     },
  404.     keyupHandler: function(){
  405.         //==========================================================
  406.         //--> NOTE: keypress does not capture backspace, delete, or enter so use keyup
  407.         //==========================================================
  408.         this.resize();
  409.     },
  410.     resize: function(){
  411.         //==========================================================
  412.         //--> First clear the height to reset the scrollHeight
  413.         //==========================================================
  414.         this.applyStyle("height", "0px");
  415.        
  416.         //==========================================================
  417.         //--> Now apply the scrollHeight to the current box
  418.         //==========================================================
  419.         this.applyStyle("height", this.node.scrollHeight + "px");
  420.     },
  421.     getDomValue: function() {
  422.         if (this.hasNode()) {
  423.             return this.node.value;
  424.         }
  425.     },
  426.     setDomValue: function(inValue) {
  427.         this.setAttribute("value", inValue);
  428.         // FIXME: it's not clear when we need to set .value vs. using setAttribute above
  429.         if (this.hasNode()) {
  430.             this.node.value = inValue;
  431.         }
  432.         if (!this.isEmpty()) {
  433.             this.addRemovePlaceholderClassName(false);
  434.         }
  435.     },
  436.     mousedownHandler: function(inSender, inEvent) {
  437.         if (this.disabled) {
  438.             inEvent.preventDefault();
  439.         }
  440.         return this.fire("mousedown", inEvent);
  441.     },
  442.     changeHandler: function(inSender, inEvent) {
  443.         // if we are re-rendered we won't show the proper value unless we capture it in domAttributes
  444.         // we don't call setAttribute (or setDomValue) because of potential side-effects of altering the DOM
  445.         this.domAttributes.value = this.getValue();
  446.         //--> Resize for auto-growth:
  447.         this.resize()
  448.         // we have the option/responsibility to propagate this event to owner
  449.         this.doChange(inEvent);
  450.     },
  451.     isEmpty: function() {
  452.         return !this.getValue();
  453.     },
  454.     getValue: function() {
  455.         if (this.hasNode()) {
  456.             var v = this.getDomValue();
  457.             if (enyo.isString(v)) {
  458.                 this.value = v;
  459.             }
  460.         }
  461.         return this.value;
  462.     },
  463.     valueChanged: function() {
  464.         this.setDomValue(this.value);
  465.         //--> Resize for auto-growth:
  466.         //this.resize()
  467.     },
  468.     disabledChanged: function() {
  469.         // NOTE: standard disabled attribute prevents all mouse events;
  470.         // this could be avoided by not using this attribute;
  471.         // however, this would make dealing with focus tab order complex
  472.         // (e.g. keyboard next focuses control: it should
  473.         // not focus, but next control after this one should)
  474.         this.setAttribute("disabled", this.disabled ? "disabled" : null);
  475.         this.addRemoveClass(this.disabledClassName, this.disabled);
  476.     },
  477.     readonlyChanged: function() {
  478.         this.setAttribute("readonly", this.readonly ? "readonly" : null);
  479.     },
  480.     placeholderChanged: function() {
  481.         this.setAttribute("placeholder", this.placeholder);
  482.     },
  483.     tabIndexChanged: function() {
  484.         this.setAttribute("tabindex", this.tabIndex);
  485.     },
  486.     focusHandler: function(inSender, e) {
  487.         this.didFocus = true;
  488.         if (this.hasNode()) {
  489.             if (this.isEmpty()) {
  490.                 this.updatePlaceholder(false);
  491.             }
  492.         }
  493.         return this.disabled ? true : this.doFocus();
  494.     },
  495.     blurHandler: function(inSender, inEvent) {
  496.         this.didFocus = false;
  497.         if (this.isEmpty()) {
  498.             this.updatePlaceholder(true);
  499.         }
  500.         return this.doBlur();
  501.     },
  502.     updatePlaceholder: function(inApplyPlaceholder) {
  503.         this.addRemovePlaceholderClassName(inApplyPlaceholder);
  504.     },
  505.     addRemovePlaceholderClassName: function(inApplyPlaceholder) {
  506.         this.addRemoveClass(this.placeholderClassName, inApplyPlaceholder);
  507.     },
  508.     //* @public
  509.     /**
  510.     Force the input to receive keyboard focus.
  511.     */
  512.     forceFocus: function(inCallback, inSync) {
  513.         // has to be async in many cases (when responding to dom events, in particular) or it just fails
  514.         if (inSync) {
  515.             this.applyFocus(inCallback);
  516.         } else {
  517.             enyo.asyncMethod(this, "applyFocus", inCallback);
  518.         }
  519.     },
  520.     //* @protected
  521.     applyFocus: function(inCallback) {
  522.         if (this.hasNode()) {
  523.             this.node.focus();
  524.             if (inCallback) {
  525.                 inCallback();
  526.             }
  527.         }
  528.     },
  529.     //* @public
  530.     /**
  531.         Forces this input to be blurred (lose focus).
  532.     */
  533.     forceBlur: function(inCallback, inSync) {
  534.         if (inSync) {
  535.             this.applyBlur(inCallback);
  536.         } else {
  537.             enyo.asyncMethod(this, "applyBlur", inCallback);
  538.         }
  539.     },
  540.     //* @protected
  541.     applyBlur: function(inCallback) {
  542.         if (this.hasNode()) {
  543.             this.node.blur();
  544.             if (inCallback) {
  545.                 inCallback();
  546.             }
  547.         }
  548.     },
  549.     //* @public
  550.     /**
  551.         Force select all text in this input.
  552.     */
  553.     forceSelect: function(inCallback, inSync) {
  554.         if (inSync) {
  555.             this.applySelect(inCallback);
  556.         } else {
  557.             enyo.asyncMethod(this, "applySelect", inCallback);
  558.         }
  559.     },
  560.     //* @protected
  561.     applySelect: function(inCallback) {
  562.         if (this.hasNode()) {
  563.             this.node.select();
  564.             if (inCallback) {
  565.                 inCallback();
  566.             }
  567.         }
  568.     },
  569.     /**
  570.         Returns true if the input has keyboard focus.
  571.     */
  572.     hasFocus: function() {
  573.         if (this.hasNode()) {
  574.             return Boolean(this.node.parentNode.querySelector(this.nodeTag +":focus"));
  575.         }
  576.     }
  577. });
  578.  
  579. // on devices with focusAtPoint api, do not need special mousedown handling.
  580. enyo.requiresWindow(function() {
  581.     //if (window.PalmSystem) {
  582.         BasicTextarea.prototype.requiresDomMousedown = false;
  583.     //}
  584. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement