Example #1
0
        _handleResetLayers: function (payload) {
            var documentID = payload.documentID,
                documentExports = this._documentExportsMap.get(documentID),
                layers = collection.pluck(payload.layers, "descriptor"),
                nextDocumentExports = documentExports.resetLayers(layers);

            this._documentExportsMap = this._documentExportsMap.set(documentID, nextDocumentExports);
            this.emit("change");
        },
Example #2
0
        _getOptions: function (type) {
            var searchTypeInfo = this._registeredSearchTypes[type];
            
            if (searchTypeInfo) {
                var items = searchTypeInfo.getOptions();
                var itemMap;

                if (items === null) {
                    itemMap = [];
                } else {
                    // Get shortest unique paths
                    var ancestors = collection.pluck(items, "pathInfo"),
                        shortenedPaths = searchTypeInfo.shortenPaths ?
                            pathUtil.getShortestUniquePaths(ancestors) : ancestors;

                    itemMap = items.map(function (item, index) {
                        var newPathInfo = shortenedPaths.get(index) || "",
                            name = item.name,
                            untitledString = nls.localize("strings.SEARCH.UNTITLED"),
                            style;
                        
                        // Don't show the path info if it is just the same as the item name 
                        if (name === newPathInfo) {
                            newPathInfo = "";
                        }

                        if (name === "") {
                            name = untitledString;
                            style = { "fontStyle": "italic" };
                        }

                        return {
                            id: type + "-" + item.id.toString(),
                            title: name,
                            pathInfo: newPathInfo,
                            svgType: item.iconID,
                            category: item.category,
                            style: style,
                            type: "item"
                        };
                    }, this);
                }

                // Label to separate groups of options
                var headerLabel = {
                    id: type + "-header",
                    title: HEADERS[type],
                    category: [],
                    type: "header"
                };

                return itemMap.unshift(headerLabel);
            }
            return Immutable.List();
        },
Example #3
0
    var registerLibrarySearch = function (libraries) {
        var libraryIDs = libraries.length > 0 ? collection.pluck(libraries, "id") : Immutable.List(),
            libraryNames = libraries.length > 0 ? collection.pluck(libraries, "name") : Immutable.List(),
            assetTypes = ["LIBRARY", "GRAPHIC", "LAYERSTYLE", "CHARACTERSTYLE"];
        
        var filters = libraryIDs.concat(assetTypes),
            displayFilters = libraryNames.concat(assetTypes);

        var payload = {
            "type": "LIBRARY",
            "getOptions": _getLibrarySearchOptions.bind(this),
            "filters": filters,
            "displayFilters": displayFilters,
            "handleExecute": _confirmSearch.bind(this),
            "shortenPaths": false,
            "getSVGClass": _getSVGClass
        };
        
        return this.dispatchAsync(events.search.REGISTER_SEARCH_PROVIDER, payload);
    };
Example #4
0
            .then(function (cefHasFocus) {
                var el = window.document.activeElement,
                    data;

                if (cefHasFocus && _isInput(el)) {
                    if (_isTextInput(el)) {
                        data = el.value.substring(el.selectionStart, el.selectionEnd);
                        if (cut) {
                            el.setRangeText("");
                        }
                    } else {
                        data = el.value;
                    }
                } else {
                    // Even if CEF doesn't have focus, a disabled input could have a selection
                    var selection = window.document.getSelection();
                    if (selection.type === "Range") {
                        data = selection.toString();
                    }
                }

                if (typeof data === "string") {
                    var cutCopyEvent = new window.Event(cut ? "cut" : "copy", { bubbles: true });
                    el.dispatchEvent(cutCopyEvent);

                    return os.clipboardWrite(data);
                }

                // If we're on modal state (type edit), we should go with native copy/cut
                if (this.flux.store("tool").getModalToolState()) {
                    if (cut) {
                        this.flux.actions.edit.nativeCut();
                    } else {
                        this.flux.actions.edit.nativeCopy();
                    }
                } else if (!cut) {
                    var applicationStore = this.flux.store("application"),
                        document = applicationStore.getCurrentDocument();

                    if (!document || document.unsupported) {
                        return;
                    }

                    var layerIDs = collection.pluck(document.layers.selectedNormalized, "id"),
                        payload = {
                            document: document.id,
                            layers: layerIDs
                        },
                        rawPayload = JSON.stringify(payload);

                    headlights.logEvent("edit", "layers", "copy_layers");
                    return os.clipboardWrite(rawPayload, LAYER_CLIPBOARD_FORMAT);
                }
            });
Example #5
0
    var _strokeChangeDispatch = function (document, layers, strokeProperties, eventName, coalesce) {
        var payload = {
            documentID: document.id,
            layerIDs: collection.pluck(layers, "id"),
            strokeProperties: strokeProperties,
            coalesce: coalesce,
            history: {
                newState: true
            }
        };

        return this.dispatchAsync(eventName, payload);
    };
Example #6
0
    var _fillChangeDispatch = function (document, layers, fillProperties, eventName, coalesce) {
        // TODO layers param needs to be made fa real
        var payload = {
            documentID: document.id,
            layerIDs: collection.pluck(layers, "id"),
            fillProperties: fillProperties,
            coalesce: coalesce,
            history: {
                newState: true
            }
        };

        return this.dispatchAsync(eventName, payload);
    };
Example #7
0
    var deleteEffect = function (document, layers, effectIndex, effectType) {
        var payload = {
            documentID: document.id,
            layerIDs: collection.pluck(layers, "id"),
            layerEffectType: effectType,
            layerEffectIndex: effectIndex,
            history: {
                newState: true,
                name: nls.localize("strings.ACTIONS.SET_LAYER_EFFECTS")
            }
        };
        // Synchronously update the stores
        this.dispatch(events.document.history.LAYER_EFFECT_DELETED, payload);

        // Then update photoshop
        return _syncStoreToPs.call(this, document, layers, null, effectType, null);
    };
Example #8
0
    var _upsertEffectProperties = function (document, layers, layerEffectIndex, newProps, coalesce, type) {
        var layerIDs = collection.pluck(layers, "id"),
            layerEffectPropsList = [],
            layerEffectIndexList = [];

        // Prepare some per-layer items for the payload
        layers.forEach(function (curLayer) {
            var curLayerEffects = curLayer.getLayerEffectsByType(type),
                curLayerEffect,
                props;

            if (curLayerEffects && curLayerEffects.has(layerEffectIndex)) {
                // updating existing layer effect
                curLayerEffect = curLayerEffects.get(layerEffectIndex);
                layerEffectIndexList.push(layerEffectIndex);
            } else {
                // adding new layer effect
                curLayerEffect = {};
                layerEffectIndexList.push(null); // will use push on top of any existing layer effects
            }

            // if newProps is a function, apply it
            props = _.isFunction(newProps) ? newProps(curLayerEffect) : newProps;
            // force it back enabled unless explicitly set to false
            props.enabled = (props.enabled === undefined) || props.enabled;
            layerEffectPropsList.push(props);
        }, this);

        var payload = {
            documentID: document.id,
            layerIDs: layerIDs,
            layerEffectType: type,
            layerEffectIndex: Immutable.List(layerEffectIndexList),
            layerEffectProperties: Immutable.List(layerEffectPropsList),
            coalesce: !!coalesce,
            history: {
                newState: true,
                name: nls.localize("strings.ACTIONS.SET_LAYER_EFFECTS")
            }
        };

        // Synchronously update the stores
        this.dispatch(events.document.history.LAYER_EFFECT_CHANGED, payload);
        // Then update photoshop
        return _syncStoreToPs.call(this, document, layers, coalesce, type);
    };
Example #9
0
    var _playCombine = function (document, layers, playObject) {
        if (layers.isEmpty()) {
            return Promise.resolve();
        }

        var dispatchPromise,
            payload = {
                documentID: document.id,
                history: {
                    newState: true,
                    name: nls.localize("strings.ACTIONS.COMBINE_SHAPES")
                }
            };

        if (layers.size > 1) {
            payload.layerIDs = collection.pluck(layers.butLast(), "id");
            dispatchPromise = this.dispatchAsync(events.document.history.DELETE_LAYERS, payload);
        } else {
            dispatchPromise = this.dispatchAsync(events.history.NEW_HISTORY_STATE, payload);
        }

        var options = {
                historyStateInfo: {
                    name: nls.localize("strings.ACTIONS.COMBINE_SHAPES"),
                    target: documentLib.referenceBy.id(document.id)
                }
            },
            playPromise = descriptor.playObject(playObject, options);

        return Promise.join(dispatchPromise, playPromise)
            .bind(this)
            .then(function () {
                if (layers.size > 1) {
                    // The "highest" layer wins but the resultant layer is shifted down 
                    // by the number of "losing" layers
                    // Important note: the resultant layer has a NEW LAYER ID
                    var winningLayerIndex = document.layers.indexOf(layers.last()),
                        adjustedLayerIndex = winningLayerIndex - layers.size + 1;

                    return this.transfer(layerActions.resetLayersByIndex, document, adjustedLayerIndex);
                } else {
                    return this.transfer(layerActions.resetLayers, document, layers);
                }
            });
    };
Example #10
0
    var _refreshStrokes = function (document, layers) {
        var layerIDs = collection.pluck(layers, "id"),
            refs = layerLib.referenceBy.id(layerIDs.toArray());

        return descriptor.batchMultiGetProperties(refs._ref, ["AGMStrokeStyleInfo"])
            .bind(this)
            .then(function (batchGetResponse) {
                if (!batchGetResponse || batchGetResponse.length !== layers.size) {
                    throw new Error("Bad response from photoshop for AGMStrokeStyleInfo batchGet");
                }
                var payload = {
                    documentID: document.id,
                    layerIDs: layerIDs,
                    strokeStyleDescriptor: Immutable.List(_.pluck(batchGetResponse, "AGMStrokeStyleInfo")),
                    history: {
                        newState: true,
                        amendRogue: true
                    }
                };
                this.dispatch(events.document.history.STROKE_ADDED, payload);
            });
    };
Example #11
0
    var duplicateLayerEffects = function (document, targetLayers, source, options) {
        targetLayers = targetLayers || document.layers.selected;

        var layerIDs = collection.pluck(targetLayers, "id"),
            masterEffectIndexMap = {}, // Immutable.Map<String, Immutable.List<Immutable.List<number>>>
            masterEffectPropsMap = {}, // Immutable.Map<String, Immutable.List<Immutable.List<object>>>
            masterEffectTypes = [], // Immutable.List<String>, for keys of above maps
            sourceEffects = _.map(source.toObject(), function (effects, effectType) {
                return {
                    type: effectType,
                    effects: effects
                };
            });
            
        // 1. Build lists to update / insert the properties from source layer to target layers
        // 
        // For each effectType
        //      For each effect at index i
        //          Build every layer's ID array, with index for that layer, and props for that layer's new effect
        // Build a different master props/index list for each effect type
        sourceEffects.forEach(function (sourceEffect) {
            var curType = sourceEffect.type,
                effectPropsList = [],
                effectIndexList = [];

            masterEffectTypes.push(curType);
            // Each effect will have either an index, or null to be inserted into each layer,
            // which are saved in effectPropsList and effectIndexList
            sourceEffect.effects.forEach(function (effectObj, effectIndex) {
                var perEffectIndexList = [],
                    perEffectPropsList = [];

                targetLayers.forEach(function (targetLayer) {
                    var targetLayerEffects = targetLayer.getLayerEffectsByType(curType),
                        newEffectProps = effectObj;

                    if (targetLayerEffects && targetLayerEffects.has(effectIndex)) {
                        // If it already exists, we can just push the ID for that effect
                        perEffectIndexList.push(effectIndex); // The order we push on these lists is the layer ordering
                    } else {
                        // If it doesn't exist, we push a null object/null index
                        // THIS IS GONNA BE A PROBLEM WITH MULTIPLES
                        perEffectIndexList.push(null); // null signifies this will be the first effect 
                    }

                    var enabled = (newEffectProps.enabled === undefined) || newEffectProps.enabled;

                    // We have to keep this immutable so we don't lose the data structures like Color in the Record
                    newEffectProps.set("enabled", enabled);

                    perEffectPropsList.push(newEffectProps);
                });
                
                effectIndexList.push(Immutable.List(perEffectIndexList));
                effectPropsList.push(Immutable.List(perEffectPropsList));
            });
            
            // Now that we've build per effect per layer lists, we can add them to master list
            masterEffectIndexMap[curType] = Immutable.List(effectIndexList);
            masterEffectPropsMap[curType] = Immutable.List(effectPropsList);
        });
        
        // 2. Expand the lists to delete the effects that are not exist in the source layer.
        masterEffectTypes.forEach(function (effectType) {
            var effectIndexList = masterEffectIndexMap[effectType],
                effectPropsMap = masterEffectPropsMap[effectType],
                sourceEffectSize = source.get(effectType).size,
                maxExistingEffectsNumber = 0;
            
            targetLayers.forEach(function (targetLayer) {
                maxExistingEffectsNumber = Math.max(targetLayer.getLayerEffectsByType(effectType).size,
                    maxExistingEffectsNumber);
            });
            
            if (sourceEffectSize < maxExistingEffectsNumber) {
                for (var i = sourceEffectSize; i < maxExistingEffectsNumber; i++) {
                    var deletedEffectIndexList = [],
                        deletedEffectPropsList = [];
                    
                    for (var j = 0; j < layerIDs.size; j++) {
                        // the index of the deleted effects are always the size of the effects in the source layer, 
                        // which is the index after the last effect. This is becuase the LayerStructure model updates 
                        // the effects index by index, and indexes may become invalid after a deletion.
                        // 
                        // For example:
                        // 
                        // 1 say we have layer effects [A, B, C]
                        // 2 we want to delete the last two effects (because they don't exist in the source layer), 
                        //   so the index may looks like [1 , 2] 
                        // 3 after layerstructure deletes the second effect (index = 1), the new layer 
                        //   effects list become [A, C]
                        // 4 when it tries to delete the third effect (index = 2), it will hit out-of-range error.
                        // 
                        // For this case, a working index list should be [1, 1]
                        deletedEffectIndexList.push(sourceEffectSize);
                        deletedEffectPropsList.push(null);
                    }
                    
                    effectIndexList = effectIndexList.push(Immutable.List(deletedEffectIndexList));
                    effectPropsMap = effectPropsMap.push(Immutable.List(deletedEffectPropsList));
                }
                
                masterEffectIndexMap[effectType] = effectIndexList;
                masterEffectPropsMap[effectType] = effectPropsMap;
            }
        });

        var payload = {
            documentID: document.id,
            layerIDs: layerIDs,
            layerEffectTypes: Immutable.List(masterEffectTypes),
            layerEffectIndex: Immutable.Map(masterEffectIndexMap),
            layerEffectProps: Immutable.Map(masterEffectPropsMap),
            coalesce: false,
            history: {
                newState: true,
                name: nls.localize("strings.ACTIONS.SET_LAYER_EFFECTS")
            }
        };

        this.dispatchAsync(events.style.HIDE_HUD);
        
        // Synchronously update the stores
        this.dispatch(events.document.history.LAYER_EFFECTS_BATCH_CHANGED, payload);
        // Then update photoshop
        return _syncStoreToPs.call(this, document, targetLayers, false, masterEffectTypes, options);
    };
Example #12
0
            .reduce(function (reducedModel, property) {
                var values = collection.pluck(paragraphStyles, property);

                reducedModel[property] = collection.uniformValue(values);
                return reducedModel;
            }, {});