From 8bea1e0807f36595d762592c030d4810396ada85 Mon Sep 17 00:00:00 2001 From: Eric Guzman Date: Wed, 2 May 2012 15:30:27 -0700 Subject: CSS Panel - Add focus management to styles view delegate --- .../css-panel/declaration.reel/declaration.js | 32 ++- .../css-style-rule.reel/css-style-rule.js | 2 +- js/panels/css-panel/style.reel/style.css | 2 +- js/panels/css-panel/style.reel/style.html | 8 + js/panels/css-panel/style.reel/style.js | 83 ++++++-- .../styles-view-container.html | 2 +- js/panels/css-panel/styles-view-delegate.js | 233 +++++++++++++++++++++ js/panels/css-panel/styles-view-mediator.js | 190 ----------------- 8 files changed, 333 insertions(+), 219 deletions(-) create mode 100644 js/panels/css-panel/styles-view-delegate.js delete mode 100644 js/panels/css-panel/styles-view-mediator.js (limited to 'js/panels') diff --git a/js/panels/css-panel/declaration.reel/declaration.js b/js/panels/css-panel/declaration.reel/declaration.js index 873d2ce4..8ab19ad6 100644 --- a/js/panels/css-panel/declaration.reel/declaration.js +++ b/js/panels/css-panel/declaration.reel/declaration.js @@ -9,6 +9,9 @@ var Montage = require("montage/core/core").Montage, ShorthandProps = require("js/panels/CSSPanel/css-shorthand-map"); exports.Declaration = Montage.create(Component, { + cssText : { + value: null + }, focusDelegate : { value: null }, @@ -42,6 +45,8 @@ exports.Declaration = Montage.create(Component, { set: function(dec) { this._declaration = dec; + this.cssText = dec.cssText; + ///// creates data structure to use with tree component this.buildStyleTree(); @@ -52,11 +57,34 @@ exports.Declaration = Montage.create(Component, { "isEmpty": true }); } -//debugger; + this.needsDraw = true; } }, + update : { + value: function() { + if(this.declaration.cssText !== this.cssText) { + ///// Needs update + this.treeController.branchControllers[0].content.forEach(function(obj) { + this.treeController.branchControllers[0].removeObjects(obj); + }, this ); + + this.buildStyleTree(); + + if(this.includeEmptyStyle) { + this.styleTree.properties.push({ + "name": "property", + "value" : "value", + "isEmpty": true + }); + } +//debugger; + this.needsDraw = true; + } + } + }, + buildStyleTree : { value: function() { var styles = Array.prototype.slice.call(this._declaration).sort(); @@ -124,8 +152,6 @@ exports.Declaration = Montage.create(Component, { addNewStyleAfter : { value: function(style) { - //this.treeController.branchControllers[0].addObjects({ - foo1 = style.parentComponent.parentComponent; style.parentComponent.parentComponent.contentController.addObjects({ name: 'property', value: 'value', diff --git a/js/panels/css-panel/rule-components/css-style-rule.reel/css-style-rule.js b/js/panels/css-panel/rule-components/css-style-rule.reel/css-style-rule.js index 7b5a736f..cfa3e605 100644 --- a/js/panels/css-panel/rule-components/css-style-rule.reel/css-style-rule.js +++ b/js/panels/css-panel/rule-components/css-style-rule.reel/css-style-rule.js @@ -90,7 +90,7 @@ exports.CssStyleRule = Montage.create(Component, { value: function() { if(this.cssText !== this.rule.cssText) { // TODO: add update for selector and stylesheet name - this.declarationComponent.update(); + //this.declarationComponent.update(); } } }, diff --git a/js/panels/css-panel/style.reel/style.css b/js/panels/css-panel/style.reel/style.css index c6bb070c..6864e245 100644 --- a/js/panels/css-panel/style.reel/style.css +++ b/js/panels/css-panel/style.reel/style.css @@ -111,7 +111,7 @@ right: -1px; } .style-item .hintable-hint { - color: #CCC; + color: #bdbdbd; } /* ------------------------ diff --git a/js/panels/css-panel/style.reel/style.html b/js/panels/css-panel/style.reel/style.html index acc169be..9830a21e 100644 --- a/js/panels/css-panel/style.reel/style.html +++ b/js/panels/css-panel/style.reel/style.html @@ -58,6 +58,10 @@ No rights, expressed or implied, whatsoever to this software are provided by Mot { "type": "change", "listener": {"@": "owner"} + }, + { + "type": "stop", + "listener": {"@": "owner"} } ] }, @@ -80,6 +84,10 @@ No rights, expressed or implied, whatsoever to this software are provided by Mot { "type": "change", "listener": {"@": "owner"} + }, + { + "type": "stop", + "listener": {"@": "owner"} } ] } diff --git a/js/panels/css-panel/style.reel/style.js b/js/panels/css-panel/style.reel/style.js index c73da6e5..1d5a11a5 100644 --- a/js/panels/css-panel/style.reel/style.js +++ b/js/panels/css-panel/style.reel/style.js @@ -8,27 +8,14 @@ var Montage = require("montage/core/core").Montage, TreeNode = require("js/components/treeview/tree-node").TreeNode; exports.Style = Montage.create(TreeNode, { - delegate : { - value: null - }, - disabledClass : { - value: 'style-item-disabled' - }, - editingStyleClass : { - value: 'edit-style-item' - }, - editNewEmptyClass : { - value: 'edit-empty-style' - }, - invalidStyleClass : { - value: "style-item-invalid" - }, - propertyText : { - value: "property" - }, - _valueText : { - value: "value" - }, + delegate : { value: null }, + disabledClass : { value: 'style-item-disabled' }, + editingStyleClass : { value: 'edit-style-item' }, + editNewEmptyClass : { value: 'edit-empty-style' }, + invalidStyleClass : { value: "style-item-invalid" }, + + propertyText : { value: "property" }, + _valueText : { value: "value" }, valueText : { get: function() { return this._valueText; @@ -158,6 +145,27 @@ exports.Style = Montage.create(TreeNode, { } }, + getSiblingStyle : { + value: function(which) { + var styles = this.parentComponent.parentComponent.childComponents.map(function(sub){ + return sub.childComponents[0]; + }), + index = styles.indexOf(this); + + switch (which) { + case "first": + return styles[0]; + case "last": + return styles[styles.length-1]; + case "next": + return (index+1 < styles.length) ? styles[index+1] : null; + case "prev": + return (index-1 >= 0) ? styles[index-1] : null; + } + } + }, + + handleEvent : { value: function(e) { console.log(e); @@ -206,11 +214,40 @@ exports.Style = Montage.create(TreeNode, { handleStart : { value: function(e) { this.editing = true; + + if(this.empty) { + this.editingNewStyle = true; + } } }, //// Handler for both hintable components - handleStop : { + handlePropertyStop : { + value: function(e) { + var event = e; + ///// Function to determine if an empty (new) style should return + ///// to showing the add button, i.e. the fields were not clicked + function fieldsClicked() { + var clicked; + if(e._event.detail.originalEventType === 'mousedown') { + clicked = e._event.detail.originalEvent.target; + return clicked === this.propertyField.element || clicked === this.valueField.element; + } + return false; + } + + this.editing = false; + + if(this.sourceObject.isEmpty && !this.dirty && !fieldsClicked.bind(this)()) { + ///// Show add button + this.editingNewStyle = false; + } + + this.delegate.handlePropertyStop(e, this); + } + }, + //// Handler for both hintable components + handleValueStop : { value: function(e) { var event = e; ///// Function to determine if an empty (new) style should return @@ -231,7 +268,7 @@ exports.Style = Montage.create(TreeNode, { this.editingNewStyle = false; } - this.delegate.handleStyleStop(e); + this.delegate.handleValueStop(e, this); } }, diff --git a/js/panels/css-panel/styles-view-container.reel/styles-view-container.html b/js/panels/css-panel/styles-view-container.reel/styles-view-container.html index 10b63087..658a8bac 100644 --- a/js/panels/css-panel/styles-view-container.reel/styles-view-container.html +++ b/js/panels/css-panel/styles-view-container.reel/styles-view-container.html @@ -38,7 +38,7 @@ No rights, expressed or implied, whatsoever to this software are provided by Mot } }, "stylesViewDelegate" : { - "module": "js/panels/css-panel/styles-view-mediator", + "module": "js/panels/css-panel/styles-view-delegate", "name": "StylesViewMediator", "properties": { "ruleListContainer": {"@": "ruleListContainer"} diff --git a/js/panels/css-panel/styles-view-delegate.js b/js/panels/css-panel/styles-view-delegate.js new file mode 100644 index 00000000..a76d25ad --- /dev/null +++ b/js/panels/css-panel/styles-view-delegate.js @@ -0,0 +1,233 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + Component = require("montage/ui/component").Component, + Keyboard = require("js/mediators/keyboard-mediator").Keyboard; + +exports.StylesViewMediator = Montage.create(Component, { + newClassPrefix : { + value: "new-class" + }, + stylesController : { + get: function() { + return this.application.ninja.stylesController; + }, + set: function(){ + return; + } + }, + + handleSelectorChange : { + value: function(rule, newSelector, ruleComponent) { + if(newSelector === "") { + //debugger; + ruleComponent.parentComponent.removeRule(ruleComponent); + return false; + } + + rule.selectorText = newSelector; + + ruleComponent.applied = this.ruleListContainer.displayedList.selection.every(function(el) { + return this._doesSelectorTargetElement(newSelector, el); + }, this); + + } + }, + + ///// Add rule button action + handleAddAction : { + value: function(e) { + var selector, + newRule, + applies = true; + + ///// Get selection prefix + if(this.ruleListContainer.displayedList.selection.length > 1) { + selector = this.stylesController.generateClassName(null, true); + } else { + selector = this.stylesController.generateClassName(this.newClassPrefix); + } + + ///// Create the rule with generated selector + newRule = this.application.ninja.stylesController.addRule('.'+selector, ' { }'); + + ///// Add the generated class to each element in selection + ///// and check whether it applies to the element + this.ruleListContainer.displayedList.selection.forEach(function(el) { + this.stylesController.addClass(el, selector); + + if(applies) { + applies = (this._doesSelectorTargetElement('.'+selector, el)); + } + },this); + + ///// Add rule directly to the rule list + this.ruleListContainer.displayedList.component.addRule(newRule).applied = applies; + + } + }, + + _doesSelectorTargetElement : { + value: function doesSelectorTargetElement(selector, element) { + var doc = element.ownerDocument, + matchingEls = Array.prototype.slice.call(doc.querySelectorAll(selector)); + return matchingEls.indexOf(element) !== -1; + } + }, + + ///// Enable/Disable Style when checkbox is clicked + handleStyleToggle : { + value: function(rule, enable, style) { + if(enable) { + this.stylesController.setStyle(rule, style.propertyText, style.valueText, style.priority); + } else { + this.stylesController.deleteStyle(rule, style.propertyText); + } + + this._dispatchChange(); + } + }, + + handlePropertyStop: { + value: function(e, style) { + var key, nextFocus; + + console.log("Handle Style Stop"); + + if(e._event.detail.type === 'keydown') { + key = e._event.detail.keyCode; + + if(key === Keyboard.ENTER || key === Keyboard.TAB) { + e._event.detail.preventDefault(); + + if(e._event.detail.shiftKey) { + nextFocus = style.getSiblingStyle('prev') || style.getSiblingStyle('last'); + nextFocus.valueField.start(); + } else { + style.valueField.start(); + } + } + } + } + }, + handleValueStop: { + value: function(e, style) { + var key, nextFocus + console.log("Handle Value Stop"); + console.log("Editing new style: ", style.editingNewStyle); + + if(e._event.detail.type === 'keydown') { + key = e._event.detail.keyCode; + + if(key === Keyboard.ENTER || key === Keyboard.TAB) { + e._event.detail.preventDefault(); + + if(e._event.detail.shiftKey) { + style.propertyField.start(); + } else { + nextFocus = style.getSiblingStyle('next'); + if(nextFocus) { + nextFocus.propertyField.start(); + } else { + style.treeView.parentComponent.addNewStyleAfter(style); + style.editingNewStyle = false; + setTimeout(function() { + style.getSiblingStyle('next').propertyField.start(); + }, 50); + } + } + } + } + } + }, + handlePropertyChange : { + value: function(rule, property, value, oldProperty, style) { + var browserValue; + + if(style.editingNewStyle) { + return false; + } + + if(property === '') { + style.remove(); + this._dispatchChange(oldProperty, browserValue); + return false; + } + + ///// Remove old property and add new one + this.stylesController.deleteStyle(rule, oldProperty); + browserValue = this.stylesController.setStyle(rule, property, value); + + ///// Mark style as invalid if the browser doesn't accept it + style.invalid = (browserValue === null); + + console.log("BrowserValue: ", browserValue, rule); + + this._dispatchChange(property, browserValue); + } + }, + handleValueChange : { + value: function(rule, property, value, style) { + var browserValue, units; + + if(value === '') { + style.remove(); + this._dispatchChange(property, browserValue); + return false; + } + + ///// Auto-fill units if not provided and units + ///// not previously stored + units = style.getUnits(value); + if(style.units && units === null && parseInt(value)) { + value += style.units; + style.valueField.value = value; + } else if (value !== '0') { + style.units = units; + } + + ///// update value + browserValue = this.stylesController.setStyle(rule, property, value); + + ///// Mark style as invalid if the browser doesn't accept it + style.invalid = (browserValue === null); + + console.log("BrowserValue: ", browserValue, rule); + + this._dispatchChange(property, browserValue); + + if(style.editingNewStyle) { + style.treeView.parentComponent.addNewStyleAfter(style); + style.editingNewStyle = false; + } + } + }, + + handlePaste : { + value: function(e) { + var text = document.execCommand('insertHTML', null, e._event.clipboardData.getData("Text")).trim(); + + if(text.matches(/([a-zA-Z-]+:[a-zA-Z-]+){,1}/)) { + + } + } + }, + + _dispatchChange : { + value: function(property, value) { + this.application.ninja.stage.updatedStage = true; + NJevent('elementChange', { + type : 'cssChange', + data: { + "prop": property, + "value": value + }, + redraw: null + }); + } + } +}); \ No newline at end of file diff --git a/js/panels/css-panel/styles-view-mediator.js b/js/panels/css-panel/styles-view-mediator.js deleted file mode 100644 index c3154db0..00000000 --- a/js/panels/css-panel/styles-view-mediator.js +++ /dev/null @@ -1,190 +0,0 @@ -/* - This file contains proprietary software owned by Motorola Mobility, Inc.
- No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
- (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. -
*/ - -var Montage = require("montage/core/core").Montage, - Component = require("montage/ui/component").Component, - Keyboard = require("js/mediators/keyboard-mediator").Keyboard; - -exports.StylesViewMediator = Montage.create(Component, { - newClassPrefix : { - value: "new-class" - }, - stylesController : { - get: function() { - return this.application.ninja.stylesController; - }, - set: function(){ - return; - } - }, - - handleSelectorChange : { - value: function(rule, newSelector, ruleComponent) { - if(newSelector === "") { - debugger; - ruleComponent.parentComponent.removeRule(ruleComponent); - return false; - } - - rule.selectorText = newSelector; - - ruleComponent.applied = this.ruleListContainer.displayedList.selection.every(function(el) { - return this._doesSelectorTargetElement(newSelector, el); - }, this); - - } - }, - - ///// Add rule button action - handleAddAction : { - value: function(e) { - var selector, - newRule, - applies = true; - - ///// Get selection prefix - if(this.ruleListContainer.displayedList.selection.length > 1) { - selector = this.stylesController.generateClassName(null, true); - } else { - selector = this.stylesController.generateClassName(this.newClassPrefix); - } - - ///// Create the rule with generated selector - newRule = this.application.ninja.stylesController.addRule('.'+selector, ' { }'); - - ///// Add the generated class to each element in selection - ///// and check whether it applies to the element - this.ruleListContainer.displayedList.selection.forEach(function(el) { - this.stylesController.addClass(el, selector); - - if(applies) { - applies = (this._doesSelectorTargetElement('.'+selector, el)); - } - },this); - - ///// Add rule directly to the rule list - this.ruleListContainer.displayedList.component.addRule(newRule).applied = applies; - - } - }, - - _doesSelectorTargetElement : { - value: function doesSelectorTargetElement(selector, element) { - var doc = element.ownerDocument, - matchingEls = Array.prototype.slice.call(doc.querySelectorAll(selector)); - return matchingEls.indexOf(element) !== -1; - } - }, - - ///// Enable/Disable Style when checkbox is clicked - handleStyleToggle : { - value: function(rule, enable, style) { - if(enable) { - this.stylesController.setStyle(rule, style.propertyText, style.valueText, style.priority); - } else { - this.stylesController.deleteStyle(rule, style.propertyText); - } - - this._dispatchChange(); - } - }, - - handleStyleStop: { - value: function(e) { - console.log("Handle Style Stop"); - //debugger; - if(e._event.detail.type === 'keydown') { - - } - } - }, - handlePropertyChange : { - value: function(rule, property, value, oldProperty, style) { - var browserValue; - - if(style.editingNewStyle) { - return false; - } - - if(property === '') { - style.remove(); - this._dispatchChange(oldProperty, browserValue); - return false; - } - - ///// Remove old property and add new one - this.stylesController.deleteStyle(rule, oldProperty); - browserValue = this.stylesController.setStyle(rule, property, value); - - ///// Mark style as invalid if the browser doesn't accept it - style.invalid = (browserValue === null); - - console.log("BrowserValue: ", browserValue, rule); - - this._dispatchChange(property, browserValue); - } - }, - handleValueChange : { - value: function(rule, property, value, style) { - var browserValue, units; - - if(value === '') { - style.remove(); - this._dispatchChange(property, browserValue); - return false; - } - - ///// Auto-fill units if not provided and units - ///// not previously stored - units = style.getUnits(value); - if(style.units && units === null && parseInt(value)) { - value += style.units; - style.valueField.value = value; - } else if (value !== '0') { - style.units = units; - } - - ///// update value - browserValue = this.stylesController.setStyle(rule, property, value); - - ///// Mark style as invalid if the browser doesn't accept it - style.invalid = (browserValue === null); - - console.log("BrowserValue: ", browserValue, rule); - - this._dispatchChange(property, browserValue); - - if(style.editingNewStyle) { - style.treeView.parentComponent.addNewStyleAfter(style); - style.editingNewStyle = false; - } - } - }, - - handlePaste : { - value: function(e) { - var text = document.execCommand('insertHTML', null, e._event.clipboardData.getData("Text")).trim(); - - if(text.matches(/([a-zA-Z-]+:[a-zA-Z-]+){,1}/)) { - - } - } - }, - - _dispatchChange : { - value: function(property, value) { - this.application.ninja.stage.updatedStage = true; - NJevent('elementChange', { - type : 'cssChange', - data: { - "prop": property, - "value": value - }, - redraw: null - }); - } - } -}); \ No newline at end of file -- cgit v1.2.3