/* 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" }, elementOutlineClass : { value: "nj-element-highlight" }, stylesController : { get: function() { return this.application.ninja.stylesController; }, set: function(){ return; } }, ///// Selector Actions //// ------------------------------------- ///// Show the targeted elements in the document by applying a class ///// temporarily handleSelectorHover : { value: function(selector, direction) { if(!selector) { return false; } var elements = this.stylesController._activeDocument._document.querySelectorAll(selector), method = (direction === "out") ? "remove" : "add"; Array.prototype.slice.call(elements).forEach(function(el) { el.classList[method](this.elementOutlineClass); }, this); } }, ///// Apply new selector to the rule //// Verify that it applies to the selected elements //// Remove rule if the selector is deleted handleSelectorChange : { value: function(rule, newSelector, ruleComponent) { if(newSelector === "") { ruleComponent.parentComponent.removeRule(ruleComponent); this.stylesController.deleteRule(rule); ///// Remove the hover style this.handleSelectorHover(rule.selectorText, 'out'); this._dispatchChange(); return false; } rule.selectorText = newSelector; ruleComponent.applied = this.ruleListContainer.displayedList.selection.every(function(el) { return this._doesSelectorTargetElement(newSelector, el); }, this); this._dispatchChange(); } }, ///// Returns true if the passed-in selector targets the passed-in element _doesSelectorTargetElement : { value: function doesSelectorTargetElement(selector, element) { var doc = element.ownerDocument, matchingEls = Array.prototype.slice.call(doc.querySelectorAll(selector)); return matchingEls.indexOf(element) !== -1; } }, ///// Style event handlers //// ------------------------------------- ///// Enable/Disable Style when checkbox is clicked handleStyleToggle : { value: function(rule, enable, style) { if(enable) { this.stylesController.setStyle(rule, style.propertyText, style.browserValue, style.priority); } else { this.stylesController.deleteStyle(rule, style.propertyText); } this._dispatchChange(); } }, handlePropertyStop: { value: function(e, style) { var key, nextFocus; if(e._event.detail.type === 'keydown' && !style.deleting) { 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; if(e._event.detail.type === 'keydown' && !style.deleting) { 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 if(style.dirty) { style.parentComponent.parentComponent.addNewStyle(); 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; } ///// Remove old property this.stylesController.deleteStyle(rule, oldProperty); if(property === '') { style.deleting = true; style.parentComponent.parentComponent.removeStyle(style.source); this._dispatchChange(oldProperty, browserValue); return false; } // now add new property browserValue = this.stylesController.setStyle(rule, property, value); ///// Mark style as invalid if the browser doesn't accept it style.invalid = (browserValue === null); this._dispatchChange(property, browserValue); } }, handleValueChange : { value: function(rule, property, value, style) { var browserValue, units; if(value === '') { ///// Remove old property style.deleting = true; this.stylesController.deleteStyle(rule, property); style.parentComponent.parentComponent.removeStyle(style.source); this._dispatchChange(property, browserValue); return false; } ///// update value browserValue = this.stylesController.setStyle(rule, property, value); style.browserValue = browserValue; ///// Mark style as invalid if the browser doesn't accept it style.invalid = (browserValue === null); this._dispatchChange(property, browserValue); } }, 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}/)) { // // } } }, /// Toolbar Button Actions /// ----------------------- ///// 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, null, applies, function(ruleComponent) { var rC = ruleComponent; setTimeout(function() { rC.selectorField.start(); },50); }); } }, ///// Show/hide computed style sub panel handleComputedAction : { value: function(e) { var container = this.ownerComponent, panelToShow = (container.contentPanel === "computed") ? "rules" : "computed"; ///// Handle showing and hiding of the add button if(panelToShow === "computed") { container.toolbar.hideButton('add'); } else { container.toolbar.showButton('add'); } container.contentPanel = panelToShow; container.handleSelectionChange(); } }, ///// Utilities //// ------------------------------------- _dispatchChange : { value: function(property, value) { this.application.ninja.stage.updatedStage = true; NJevent('elementChange', { type : 'cssChange', data: { "prop": property, "value": value }, redraw: null }); } } });